1da0c48c4Sopenharmony_ci/* Locate source files and line information for given addresses
2da0c48c4Sopenharmony_ci   Copyright (C) 2005-2010, 2012, 2013, 2015 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org>
4da0c48c4Sopenharmony_ci   This file is part of elfutils.
5da0c48c4Sopenharmony_ci   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
6da0c48c4Sopenharmony_ci
7da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
8da0c48c4Sopenharmony_ci   it under the terms of the GNU General Public License as published by
9da0c48c4Sopenharmony_ci   the Free Software Foundation; either version 3 of the License, or
10da0c48c4Sopenharmony_ci   (at your option) any later version.
11da0c48c4Sopenharmony_ci
12da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
13da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
14da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15da0c48c4Sopenharmony_ci   GNU General Public License for more details.
16da0c48c4Sopenharmony_ci
17da0c48c4Sopenharmony_ci   You should have received a copy of the GNU General Public License
18da0c48c4Sopenharmony_ci   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19da0c48c4Sopenharmony_ci
20da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
21da0c48c4Sopenharmony_ci# include <config.h>
22da0c48c4Sopenharmony_ci#endif
23da0c48c4Sopenharmony_ci
24da0c48c4Sopenharmony_ci#include <argp.h>
25da0c48c4Sopenharmony_ci#include <assert.h>
26da0c48c4Sopenharmony_ci#include <errno.h>
27da0c48c4Sopenharmony_ci#include <fcntl.h>
28da0c48c4Sopenharmony_ci#include <inttypes.h>
29da0c48c4Sopenharmony_ci#include <libdwfl.h>
30da0c48c4Sopenharmony_ci#include <dwarf.h>
31da0c48c4Sopenharmony_ci#include <locale.h>
32da0c48c4Sopenharmony_ci#include <stdbool.h>
33da0c48c4Sopenharmony_ci#include <stdio.h>
34da0c48c4Sopenharmony_ci#include <stdio_ext.h>
35da0c48c4Sopenharmony_ci#include <stdlib.h>
36da0c48c4Sopenharmony_ci#include <string.h>
37da0c48c4Sopenharmony_ci#include <unistd.h>
38da0c48c4Sopenharmony_ci
39da0c48c4Sopenharmony_ci#include <system.h>
40da0c48c4Sopenharmony_ci#include <printversion.h>
41da0c48c4Sopenharmony_ci
42da0c48c4Sopenharmony_ci
43da0c48c4Sopenharmony_ci/* Name and version of program.  */
44da0c48c4Sopenharmony_ciARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
45da0c48c4Sopenharmony_ci
46da0c48c4Sopenharmony_ci/* Bug report address.  */
47da0c48c4Sopenharmony_ciARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
48da0c48c4Sopenharmony_ci
49da0c48c4Sopenharmony_ci
50da0c48c4Sopenharmony_ci/* Values for the parameters which have no short form.  */
51da0c48c4Sopenharmony_ci#define OPT_DEMANGLER 0x100
52da0c48c4Sopenharmony_ci#define OPT_PRETTY    0x101  /* 'p' is already used to select the process.  */
53da0c48c4Sopenharmony_ci#define OPT_RELATIVE  0x102  /* 'r' is something else in binutils addr2line.  */
54da0c48c4Sopenharmony_ci
55da0c48c4Sopenharmony_ci/* Definitions of arguments for argp functions.  */
56da0c48c4Sopenharmony_cistatic const struct argp_option options[] =
57da0c48c4Sopenharmony_ci{
58da0c48c4Sopenharmony_ci  { NULL, 0, NULL, 0, N_("Input format options:"), 2 },
59da0c48c4Sopenharmony_ci  { "section", 'j', "NAME", 0,
60da0c48c4Sopenharmony_ci    N_("Treat addresses as offsets relative to NAME section."), 0 },
61da0c48c4Sopenharmony_ci
62da0c48c4Sopenharmony_ci  { NULL, 0, NULL, 0, N_("Output format options:"), 3 },
63da0c48c4Sopenharmony_ci  { "addresses", 'a', NULL, 0, N_("Print address before each entry"), 0 },
64da0c48c4Sopenharmony_ci  { "basenames", 's', NULL, 0, N_("Show only base names of source files"), 0 },
65da0c48c4Sopenharmony_ci  { "absolute", 'A', NULL, 0,
66da0c48c4Sopenharmony_ci    N_("Show absolute file names using compilation directory (default)"), 0 },
67da0c48c4Sopenharmony_ci  { "functions", 'f', NULL, 0, N_("Also show function names"), 0 },
68da0c48c4Sopenharmony_ci  { "symbols", 'S', NULL, 0, N_("Also show symbol or section names"), 0 },
69da0c48c4Sopenharmony_ci  { "symbols-sections", 'x', NULL, 0, N_("Also show symbol and the section names"), 0 },
70da0c48c4Sopenharmony_ci  { "flags", 'F', NULL, 0, N_("Also show line table flags"), 0 },
71da0c48c4Sopenharmony_ci  { "inlines", 'i', NULL, 0,
72da0c48c4Sopenharmony_ci    N_("Show all source locations that caused inline expansion of subroutines at the address."),
73da0c48c4Sopenharmony_ci    0 },
74da0c48c4Sopenharmony_ci  { "demangle", 'C', "ARG", OPTION_ARG_OPTIONAL,
75da0c48c4Sopenharmony_ci    N_("Show demangled symbols (ARG is always ignored)"), 0 },
76da0c48c4Sopenharmony_ci  { "pretty-print", OPT_PRETTY, NULL, 0,
77da0c48c4Sopenharmony_ci    N_("Print all information on one line, and indent inlines"), 0 },
78da0c48c4Sopenharmony_ci  { "relative", OPT_RELATIVE, NULL, 0,
79da0c48c4Sopenharmony_ci    N_("Show relative file names without compilation directory"), 0 },
80da0c48c4Sopenharmony_ci
81da0c48c4Sopenharmony_ci  { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
82da0c48c4Sopenharmony_ci  /* Unsupported options.  */
83da0c48c4Sopenharmony_ci  { "target", 'b', "ARG", OPTION_HIDDEN, NULL, 0 },
84da0c48c4Sopenharmony_ci  { "demangler", OPT_DEMANGLER, "ARG", OPTION_HIDDEN, NULL, 0 },
85da0c48c4Sopenharmony_ci  { NULL, 0, NULL, 0, NULL, 0 }
86da0c48c4Sopenharmony_ci};
87da0c48c4Sopenharmony_ci
88da0c48c4Sopenharmony_ci/* Short description of program.  */
89da0c48c4Sopenharmony_cistatic const char doc[] = N_("\
90da0c48c4Sopenharmony_ciLocate source files and line information for ADDRs (in a.out by default).");
91da0c48c4Sopenharmony_ci
92da0c48c4Sopenharmony_ci/* Strings for arguments in help texts.  */
93da0c48c4Sopenharmony_cistatic const char args_doc[] = N_("[ADDR...]");
94da0c48c4Sopenharmony_ci
95da0c48c4Sopenharmony_ci/* Prototype for option handler.  */
96da0c48c4Sopenharmony_cistatic error_t parse_opt (int key, char *arg, struct argp_state *state);
97da0c48c4Sopenharmony_ci
98da0c48c4Sopenharmony_cistatic struct argp_child argp_children[2]; /* [0] is set in main.  */
99da0c48c4Sopenharmony_ci
100da0c48c4Sopenharmony_ci/* Data structure to communicate with argp functions.  */
101da0c48c4Sopenharmony_cistatic const struct argp argp =
102da0c48c4Sopenharmony_ci{
103da0c48c4Sopenharmony_ci  options, parse_opt, args_doc, doc, argp_children, NULL, NULL
104da0c48c4Sopenharmony_ci};
105da0c48c4Sopenharmony_ci
106da0c48c4Sopenharmony_ci
107da0c48c4Sopenharmony_ci/* Handle ADDR.  */
108da0c48c4Sopenharmony_cistatic int handle_address (const char *addr, Dwfl *dwfl);
109da0c48c4Sopenharmony_ci
110da0c48c4Sopenharmony_ci/* True when we should print the address for each entry.  */
111da0c48c4Sopenharmony_cistatic bool print_addresses;
112da0c48c4Sopenharmony_ci
113da0c48c4Sopenharmony_ci/* True if only base names of files should be shown.  */
114da0c48c4Sopenharmony_cistatic bool only_basenames;
115da0c48c4Sopenharmony_ci
116da0c48c4Sopenharmony_ci/* True if absolute file names based on DW_AT_comp_dir should be shown.  */
117da0c48c4Sopenharmony_cistatic bool use_comp_dir = true;
118da0c48c4Sopenharmony_ci
119da0c48c4Sopenharmony_ci/* True if line flags should be shown.  */
120da0c48c4Sopenharmony_cistatic bool show_flags;
121da0c48c4Sopenharmony_ci
122da0c48c4Sopenharmony_ci/* True if function names should be shown.  */
123da0c48c4Sopenharmony_cistatic bool show_functions;
124da0c48c4Sopenharmony_ci
125da0c48c4Sopenharmony_ci/* True if ELF symbol or section info should be shown.  */
126da0c48c4Sopenharmony_cistatic bool show_symbols;
127da0c48c4Sopenharmony_ci
128da0c48c4Sopenharmony_ci/* True if section associated with a symbol address should be shown.  */
129da0c48c4Sopenharmony_cistatic bool show_symbol_sections;
130da0c48c4Sopenharmony_ci
131da0c48c4Sopenharmony_ci/* If non-null, take address parameters as relative to named section.  */
132da0c48c4Sopenharmony_cistatic const char *just_section;
133da0c48c4Sopenharmony_ci
134da0c48c4Sopenharmony_ci/* True if all inlined subroutines of the current address should be shown.  */
135da0c48c4Sopenharmony_cistatic bool show_inlines;
136da0c48c4Sopenharmony_ci
137da0c48c4Sopenharmony_ci/* True if all names need to be demangled.  */
138da0c48c4Sopenharmony_cistatic bool demangle;
139da0c48c4Sopenharmony_ci
140da0c48c4Sopenharmony_ci/* True if all information should be printed on one line.  */
141da0c48c4Sopenharmony_cistatic bool pretty;
142da0c48c4Sopenharmony_ci
143da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE
144da0c48c4Sopenharmony_cistatic size_t demangle_buffer_len = 0;
145da0c48c4Sopenharmony_cistatic char *demangle_buffer = NULL;
146da0c48c4Sopenharmony_ci#endif
147da0c48c4Sopenharmony_ci
148da0c48c4Sopenharmony_ciint
149da0c48c4Sopenharmony_cimain (int argc, char *argv[])
150da0c48c4Sopenharmony_ci{
151da0c48c4Sopenharmony_ci  int remaining;
152da0c48c4Sopenharmony_ci  int result = 0;
153da0c48c4Sopenharmony_ci
154da0c48c4Sopenharmony_ci  /* We use no threads here which can interfere with handling a stream.  */
155da0c48c4Sopenharmony_ci  (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
156da0c48c4Sopenharmony_ci
157da0c48c4Sopenharmony_ci  /* Set locale.  */
158da0c48c4Sopenharmony_ci  (void) setlocale (LC_ALL, "");
159da0c48c4Sopenharmony_ci
160da0c48c4Sopenharmony_ci  /* Make sure the message catalog can be found.  */
161da0c48c4Sopenharmony_ci  (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
162da0c48c4Sopenharmony_ci
163da0c48c4Sopenharmony_ci  /* Initialize the message catalog.  */
164da0c48c4Sopenharmony_ci  (void) textdomain (PACKAGE_TARNAME);
165da0c48c4Sopenharmony_ci
166da0c48c4Sopenharmony_ci  /* Parse and process arguments.  This includes opening the modules.  */
167da0c48c4Sopenharmony_ci  argp_children[0].argp = dwfl_standard_argp ();
168da0c48c4Sopenharmony_ci  argp_children[0].group = 1;
169da0c48c4Sopenharmony_ci  Dwfl *dwfl = NULL;
170da0c48c4Sopenharmony_ci  (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
171da0c48c4Sopenharmony_ci  assert (dwfl != NULL);
172da0c48c4Sopenharmony_ci
173da0c48c4Sopenharmony_ci  /* Now handle the addresses.  In case none are given on the command
174da0c48c4Sopenharmony_ci     line, read from stdin.  */
175da0c48c4Sopenharmony_ci  if (remaining == argc)
176da0c48c4Sopenharmony_ci    {
177da0c48c4Sopenharmony_ci      /* We use no threads here which can interfere with handling a stream.  */
178da0c48c4Sopenharmony_ci      (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
179da0c48c4Sopenharmony_ci
180da0c48c4Sopenharmony_ci      char *buf = NULL;
181da0c48c4Sopenharmony_ci      size_t len = 0;
182da0c48c4Sopenharmony_ci      ssize_t chars;
183da0c48c4Sopenharmony_ci      while (!feof_unlocked (stdin))
184da0c48c4Sopenharmony_ci	{
185da0c48c4Sopenharmony_ci	  if ((chars = getline (&buf, &len, stdin)) < 0)
186da0c48c4Sopenharmony_ci	    break;
187da0c48c4Sopenharmony_ci
188da0c48c4Sopenharmony_ci	  if (buf[chars - 1] == '\n')
189da0c48c4Sopenharmony_ci	    buf[chars - 1] = '\0';
190da0c48c4Sopenharmony_ci
191da0c48c4Sopenharmony_ci	  result = handle_address (buf, dwfl);
192da0c48c4Sopenharmony_ci	  fflush (stdout);
193da0c48c4Sopenharmony_ci	}
194da0c48c4Sopenharmony_ci
195da0c48c4Sopenharmony_ci      free (buf);
196da0c48c4Sopenharmony_ci    }
197da0c48c4Sopenharmony_ci  else
198da0c48c4Sopenharmony_ci    {
199da0c48c4Sopenharmony_ci      do
200da0c48c4Sopenharmony_ci	result = handle_address (argv[remaining], dwfl);
201da0c48c4Sopenharmony_ci      while (++remaining < argc);
202da0c48c4Sopenharmony_ci    }
203da0c48c4Sopenharmony_ci
204da0c48c4Sopenharmony_ci  dwfl_end (dwfl);
205da0c48c4Sopenharmony_ci
206da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE
207da0c48c4Sopenharmony_ci  free (demangle_buffer);
208da0c48c4Sopenharmony_ci#endif
209da0c48c4Sopenharmony_ci
210da0c48c4Sopenharmony_ci  return result;
211da0c48c4Sopenharmony_ci}
212da0c48c4Sopenharmony_ci
213da0c48c4Sopenharmony_ci
214da0c48c4Sopenharmony_ci/* Handle program arguments.  */
215da0c48c4Sopenharmony_cistatic error_t
216da0c48c4Sopenharmony_ciparse_opt (int key, char *arg, struct argp_state *state)
217da0c48c4Sopenharmony_ci{
218da0c48c4Sopenharmony_ci  switch (key)
219da0c48c4Sopenharmony_ci    {
220da0c48c4Sopenharmony_ci    case ARGP_KEY_INIT:
221da0c48c4Sopenharmony_ci      state->child_inputs[0] = state->input;
222da0c48c4Sopenharmony_ci      break;
223da0c48c4Sopenharmony_ci
224da0c48c4Sopenharmony_ci    case 'a':
225da0c48c4Sopenharmony_ci      print_addresses = true;
226da0c48c4Sopenharmony_ci      break;
227da0c48c4Sopenharmony_ci
228da0c48c4Sopenharmony_ci    case 'b':
229da0c48c4Sopenharmony_ci    case 'C':
230da0c48c4Sopenharmony_ci    case OPT_DEMANGLER:
231da0c48c4Sopenharmony_ci      demangle = true;
232da0c48c4Sopenharmony_ci      break;
233da0c48c4Sopenharmony_ci
234da0c48c4Sopenharmony_ci    case 's':
235da0c48c4Sopenharmony_ci      only_basenames = true;
236da0c48c4Sopenharmony_ci      break;
237da0c48c4Sopenharmony_ci
238da0c48c4Sopenharmony_ci    case 'A':
239da0c48c4Sopenharmony_ci      use_comp_dir = true;
240da0c48c4Sopenharmony_ci      break;
241da0c48c4Sopenharmony_ci
242da0c48c4Sopenharmony_ci    case OPT_RELATIVE:
243da0c48c4Sopenharmony_ci      use_comp_dir = false;
244da0c48c4Sopenharmony_ci      break;
245da0c48c4Sopenharmony_ci
246da0c48c4Sopenharmony_ci    case 'f':
247da0c48c4Sopenharmony_ci      show_functions = true;
248da0c48c4Sopenharmony_ci      break;
249da0c48c4Sopenharmony_ci
250da0c48c4Sopenharmony_ci    case 'F':
251da0c48c4Sopenharmony_ci      show_flags = true;
252da0c48c4Sopenharmony_ci      break;
253da0c48c4Sopenharmony_ci
254da0c48c4Sopenharmony_ci    case 'S':
255da0c48c4Sopenharmony_ci      show_symbols = true;
256da0c48c4Sopenharmony_ci      break;
257da0c48c4Sopenharmony_ci
258da0c48c4Sopenharmony_ci    case 'x':
259da0c48c4Sopenharmony_ci      show_symbols = true;
260da0c48c4Sopenharmony_ci      show_symbol_sections = true;
261da0c48c4Sopenharmony_ci      break;
262da0c48c4Sopenharmony_ci
263da0c48c4Sopenharmony_ci    case 'j':
264da0c48c4Sopenharmony_ci      just_section = arg;
265da0c48c4Sopenharmony_ci      break;
266da0c48c4Sopenharmony_ci
267da0c48c4Sopenharmony_ci    case 'i':
268da0c48c4Sopenharmony_ci      show_inlines = true;
269da0c48c4Sopenharmony_ci      break;
270da0c48c4Sopenharmony_ci
271da0c48c4Sopenharmony_ci    case OPT_PRETTY:
272da0c48c4Sopenharmony_ci      pretty = true;
273da0c48c4Sopenharmony_ci      break;
274da0c48c4Sopenharmony_ci
275da0c48c4Sopenharmony_ci    default:
276da0c48c4Sopenharmony_ci      return ARGP_ERR_UNKNOWN;
277da0c48c4Sopenharmony_ci    }
278da0c48c4Sopenharmony_ci  return 0;
279da0c48c4Sopenharmony_ci}
280da0c48c4Sopenharmony_ci
281da0c48c4Sopenharmony_cistatic const char *
282da0c48c4Sopenharmony_cisymname (const char *name)
283da0c48c4Sopenharmony_ci{
284da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE
285da0c48c4Sopenharmony_ci  // Require GNU v3 ABI by the "_Z" prefix.
286da0c48c4Sopenharmony_ci  if (demangle && name[0] == '_' && name[1] == 'Z')
287da0c48c4Sopenharmony_ci    {
288da0c48c4Sopenharmony_ci      int status = -1;
289da0c48c4Sopenharmony_ci      char *dsymname = __cxa_demangle (name, demangle_buffer,
290da0c48c4Sopenharmony_ci				       &demangle_buffer_len, &status);
291da0c48c4Sopenharmony_ci      if (status == 0)
292da0c48c4Sopenharmony_ci	name = demangle_buffer = dsymname;
293da0c48c4Sopenharmony_ci    }
294da0c48c4Sopenharmony_ci#endif
295da0c48c4Sopenharmony_ci  return name;
296da0c48c4Sopenharmony_ci}
297da0c48c4Sopenharmony_ci
298da0c48c4Sopenharmony_cistatic const char *
299da0c48c4Sopenharmony_ciget_diename (Dwarf_Die *die)
300da0c48c4Sopenharmony_ci{
301da0c48c4Sopenharmony_ci  Dwarf_Attribute attr;
302da0c48c4Sopenharmony_ci  const char *name;
303da0c48c4Sopenharmony_ci
304da0c48c4Sopenharmony_ci  name = dwarf_formstring (dwarf_attr_integrate (die, DW_AT_MIPS_linkage_name,
305da0c48c4Sopenharmony_ci						 &attr)
306da0c48c4Sopenharmony_ci			   ?: dwarf_attr_integrate (die, DW_AT_linkage_name,
307da0c48c4Sopenharmony_ci						    &attr));
308da0c48c4Sopenharmony_ci
309da0c48c4Sopenharmony_ci  if (name == NULL)
310da0c48c4Sopenharmony_ci    name = dwarf_diename (die) ?: "??";
311da0c48c4Sopenharmony_ci
312da0c48c4Sopenharmony_ci  return name;
313da0c48c4Sopenharmony_ci}
314da0c48c4Sopenharmony_ci
315da0c48c4Sopenharmony_cistatic bool
316da0c48c4Sopenharmony_ciprint_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
317da0c48c4Sopenharmony_ci{
318da0c48c4Sopenharmony_ci  Dwarf_Addr bias = 0;
319da0c48c4Sopenharmony_ci  Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias);
320da0c48c4Sopenharmony_ci
321da0c48c4Sopenharmony_ci  Dwarf_Die *scopes;
322da0c48c4Sopenharmony_ci  int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes);
323da0c48c4Sopenharmony_ci  if (nscopes <= 0)
324da0c48c4Sopenharmony_ci    return false;
325da0c48c4Sopenharmony_ci
326da0c48c4Sopenharmony_ci  bool res = false;
327da0c48c4Sopenharmony_ci  for (int i = 0; i < nscopes; ++i)
328da0c48c4Sopenharmony_ci    switch (dwarf_tag (&scopes[i]))
329da0c48c4Sopenharmony_ci      {
330da0c48c4Sopenharmony_ci      case DW_TAG_subprogram:
331da0c48c4Sopenharmony_ci	{
332da0c48c4Sopenharmony_ci	  const char *name = get_diename (&scopes[i]);
333da0c48c4Sopenharmony_ci	  if (name == NULL)
334da0c48c4Sopenharmony_ci	    goto done;
335da0c48c4Sopenharmony_ci	  printf ("%s%c", symname (name), pretty ? ' ' : '\n');
336da0c48c4Sopenharmony_ci	  res = true;
337da0c48c4Sopenharmony_ci	  goto done;
338da0c48c4Sopenharmony_ci	}
339da0c48c4Sopenharmony_ci
340da0c48c4Sopenharmony_ci      case DW_TAG_inlined_subroutine:
341da0c48c4Sopenharmony_ci	{
342da0c48c4Sopenharmony_ci	  const char *name = get_diename (&scopes[i]);
343da0c48c4Sopenharmony_ci	  if (name == NULL)
344da0c48c4Sopenharmony_ci	    goto done;
345da0c48c4Sopenharmony_ci
346da0c48c4Sopenharmony_ci	  /* When using --pretty-print we only show inlines on their
347da0c48c4Sopenharmony_ci	     own line.  Just print the first subroutine name.  */
348da0c48c4Sopenharmony_ci	  if (pretty)
349da0c48c4Sopenharmony_ci	    {
350da0c48c4Sopenharmony_ci	      printf ("%s ", symname (name));
351da0c48c4Sopenharmony_ci	      res = true;
352da0c48c4Sopenharmony_ci	      goto done;
353da0c48c4Sopenharmony_ci	    }
354da0c48c4Sopenharmony_ci	  else
355da0c48c4Sopenharmony_ci	    printf ("%s inlined", symname (name));
356da0c48c4Sopenharmony_ci
357da0c48c4Sopenharmony_ci	  Dwarf_Files *files;
358da0c48c4Sopenharmony_ci	  if (dwarf_getsrcfiles (cudie, &files, NULL) == 0)
359da0c48c4Sopenharmony_ci	    {
360da0c48c4Sopenharmony_ci	      Dwarf_Attribute attr_mem;
361da0c48c4Sopenharmony_ci	      Dwarf_Word val;
362da0c48c4Sopenharmony_ci	      if (dwarf_formudata (dwarf_attr (&scopes[i],
363da0c48c4Sopenharmony_ci					       DW_AT_call_file,
364da0c48c4Sopenharmony_ci					       &attr_mem), &val) == 0)
365da0c48c4Sopenharmony_ci		{
366da0c48c4Sopenharmony_ci		  const char *file = dwarf_filesrc (files, val, NULL, NULL);
367da0c48c4Sopenharmony_ci		  unsigned int lineno = 0;
368da0c48c4Sopenharmony_ci		  unsigned int colno = 0;
369da0c48c4Sopenharmony_ci		  if (dwarf_formudata (dwarf_attr (&scopes[i],
370da0c48c4Sopenharmony_ci						   DW_AT_call_line,
371da0c48c4Sopenharmony_ci						   &attr_mem), &val) == 0)
372da0c48c4Sopenharmony_ci		    lineno = val;
373da0c48c4Sopenharmony_ci		  if (dwarf_formudata (dwarf_attr (&scopes[i],
374da0c48c4Sopenharmony_ci						   DW_AT_call_column,
375da0c48c4Sopenharmony_ci						   &attr_mem), &val) == 0)
376da0c48c4Sopenharmony_ci		    colno = val;
377da0c48c4Sopenharmony_ci
378da0c48c4Sopenharmony_ci		  const char *comp_dir = "";
379da0c48c4Sopenharmony_ci		  const char *comp_dir_sep = "";
380da0c48c4Sopenharmony_ci
381da0c48c4Sopenharmony_ci		  if (file == NULL)
382da0c48c4Sopenharmony_ci		    file = "???";
383da0c48c4Sopenharmony_ci		  else if (only_basenames)
384da0c48c4Sopenharmony_ci		    file = basename (file);
385da0c48c4Sopenharmony_ci		  else if (use_comp_dir && file[0] != '/')
386da0c48c4Sopenharmony_ci		    {
387da0c48c4Sopenharmony_ci		      const char *const *dirs;
388da0c48c4Sopenharmony_ci		      size_t ndirs;
389da0c48c4Sopenharmony_ci		      if (dwarf_getsrcdirs (files, &dirs, &ndirs) == 0
390da0c48c4Sopenharmony_ci			  && dirs[0] != NULL)
391da0c48c4Sopenharmony_ci			{
392da0c48c4Sopenharmony_ci			  comp_dir = dirs[0];
393da0c48c4Sopenharmony_ci			  comp_dir_sep = "/";
394da0c48c4Sopenharmony_ci			}
395da0c48c4Sopenharmony_ci		    }
396da0c48c4Sopenharmony_ci
397da0c48c4Sopenharmony_ci		  if (lineno == 0)
398da0c48c4Sopenharmony_ci		    printf (" from %s%s%s",
399da0c48c4Sopenharmony_ci			    comp_dir, comp_dir_sep, file);
400da0c48c4Sopenharmony_ci		  else if (colno == 0)
401da0c48c4Sopenharmony_ci		    printf (" at %s%s%s:%u",
402da0c48c4Sopenharmony_ci			    comp_dir, comp_dir_sep, file, lineno);
403da0c48c4Sopenharmony_ci		  else
404da0c48c4Sopenharmony_ci		    printf (" at %s%s%s:%u:%u",
405da0c48c4Sopenharmony_ci			    comp_dir, comp_dir_sep, file, lineno, colno);
406da0c48c4Sopenharmony_ci		}
407da0c48c4Sopenharmony_ci	    }
408da0c48c4Sopenharmony_ci	  printf (" in ");
409da0c48c4Sopenharmony_ci	  continue;
410da0c48c4Sopenharmony_ci	}
411da0c48c4Sopenharmony_ci      }
412da0c48c4Sopenharmony_ci
413da0c48c4Sopenharmony_cidone:
414da0c48c4Sopenharmony_ci  free (scopes);
415da0c48c4Sopenharmony_ci  return res;
416da0c48c4Sopenharmony_ci}
417da0c48c4Sopenharmony_ci
418da0c48c4Sopenharmony_cistatic void
419da0c48c4Sopenharmony_ciprint_addrsym (Dwfl_Module *mod, GElf_Addr addr)
420da0c48c4Sopenharmony_ci{
421da0c48c4Sopenharmony_ci  GElf_Sym s;
422da0c48c4Sopenharmony_ci  GElf_Off off;
423da0c48c4Sopenharmony_ci  const char *name = dwfl_module_addrinfo (mod, addr, &off, &s,
424da0c48c4Sopenharmony_ci					   NULL, NULL, NULL);
425da0c48c4Sopenharmony_ci  if (name == NULL)
426da0c48c4Sopenharmony_ci    {
427da0c48c4Sopenharmony_ci      /* No symbol name.  Get a section name instead.  */
428da0c48c4Sopenharmony_ci      int i = dwfl_module_relocate_address (mod, &addr);
429da0c48c4Sopenharmony_ci      if (i >= 0)
430da0c48c4Sopenharmony_ci	name = dwfl_module_relocation_info (mod, i, NULL);
431da0c48c4Sopenharmony_ci      if (name == NULL)
432da0c48c4Sopenharmony_ci	printf ("??%c", pretty ? ' ': '\n');
433da0c48c4Sopenharmony_ci      else
434da0c48c4Sopenharmony_ci	printf ("(%s)+%#" PRIx64 "%c", name, addr, pretty ? ' ' : '\n');
435da0c48c4Sopenharmony_ci    }
436da0c48c4Sopenharmony_ci  else
437da0c48c4Sopenharmony_ci    {
438da0c48c4Sopenharmony_ci      name = symname (name);
439da0c48c4Sopenharmony_ci      if (off == 0)
440da0c48c4Sopenharmony_ci	printf ("%s", name);
441da0c48c4Sopenharmony_ci      else
442da0c48c4Sopenharmony_ci	printf ("%s+%#" PRIx64 "", name, off);
443da0c48c4Sopenharmony_ci
444da0c48c4Sopenharmony_ci      // Also show section name for address.
445da0c48c4Sopenharmony_ci      if (show_symbol_sections)
446da0c48c4Sopenharmony_ci	{
447da0c48c4Sopenharmony_ci	  Dwarf_Addr ebias;
448da0c48c4Sopenharmony_ci	  Elf_Scn *scn = dwfl_module_address_section (mod, &addr, &ebias);
449da0c48c4Sopenharmony_ci	  if (scn != NULL)
450da0c48c4Sopenharmony_ci	    {
451da0c48c4Sopenharmony_ci	      GElf_Shdr shdr_mem;
452da0c48c4Sopenharmony_ci	      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
453da0c48c4Sopenharmony_ci	      if (shdr != NULL)
454da0c48c4Sopenharmony_ci		{
455da0c48c4Sopenharmony_ci		  Elf *elf = dwfl_module_getelf (mod, &ebias);
456da0c48c4Sopenharmony_ci		  size_t shstrndx;
457da0c48c4Sopenharmony_ci		  if (elf_getshdrstrndx (elf, &shstrndx) >= 0)
458da0c48c4Sopenharmony_ci		    printf (" (%s)", elf_strptr (elf, shstrndx,
459da0c48c4Sopenharmony_ci						 shdr->sh_name));
460da0c48c4Sopenharmony_ci		}
461da0c48c4Sopenharmony_ci	    }
462da0c48c4Sopenharmony_ci	}
463da0c48c4Sopenharmony_ci      printf ("%c", pretty ? ' ' : '\n');
464da0c48c4Sopenharmony_ci    }
465da0c48c4Sopenharmony_ci}
466da0c48c4Sopenharmony_ci
467da0c48c4Sopenharmony_cistatic int
468da0c48c4Sopenharmony_cisee_one_module (Dwfl_Module *mod,
469da0c48c4Sopenharmony_ci		void **userdata __attribute__ ((unused)),
470da0c48c4Sopenharmony_ci		const char *name __attribute__ ((unused)),
471da0c48c4Sopenharmony_ci		Dwarf_Addr start __attribute__ ((unused)),
472da0c48c4Sopenharmony_ci		void *arg)
473da0c48c4Sopenharmony_ci{
474da0c48c4Sopenharmony_ci  Dwfl_Module **result = arg;
475da0c48c4Sopenharmony_ci  if (*result != NULL)
476da0c48c4Sopenharmony_ci    return DWARF_CB_ABORT;
477da0c48c4Sopenharmony_ci  *result = mod;
478da0c48c4Sopenharmony_ci  return DWARF_CB_OK;
479da0c48c4Sopenharmony_ci}
480da0c48c4Sopenharmony_ci
481da0c48c4Sopenharmony_cistatic int
482da0c48c4Sopenharmony_cifind_symbol (Dwfl_Module *mod,
483da0c48c4Sopenharmony_ci	     void **userdata __attribute__ ((unused)),
484da0c48c4Sopenharmony_ci	     const char *name __attribute__ ((unused)),
485da0c48c4Sopenharmony_ci	     Dwarf_Addr start __attribute__ ((unused)),
486da0c48c4Sopenharmony_ci	     void *arg)
487da0c48c4Sopenharmony_ci{
488da0c48c4Sopenharmony_ci  const char *looking_for = ((void **) arg)[0];
489da0c48c4Sopenharmony_ci  GElf_Sym *symbol = ((void **) arg)[1];
490da0c48c4Sopenharmony_ci  GElf_Addr *value = ((void **) arg)[2];
491da0c48c4Sopenharmony_ci
492da0c48c4Sopenharmony_ci  int n = dwfl_module_getsymtab (mod);
493da0c48c4Sopenharmony_ci  for (int i = 1; i < n; ++i)
494da0c48c4Sopenharmony_ci    {
495da0c48c4Sopenharmony_ci      const char *symbol_name = dwfl_module_getsym_info (mod, i, symbol,
496da0c48c4Sopenharmony_ci							 value, NULL, NULL,
497da0c48c4Sopenharmony_ci							 NULL);
498da0c48c4Sopenharmony_ci      if (symbol_name == NULL || symbol_name[0] == '\0')
499da0c48c4Sopenharmony_ci	continue;
500da0c48c4Sopenharmony_ci      switch (GELF_ST_TYPE (symbol->st_info))
501da0c48c4Sopenharmony_ci	{
502da0c48c4Sopenharmony_ci	case STT_SECTION:
503da0c48c4Sopenharmony_ci	case STT_FILE:
504da0c48c4Sopenharmony_ci	case STT_TLS:
505da0c48c4Sopenharmony_ci	  break;
506da0c48c4Sopenharmony_ci	default:
507da0c48c4Sopenharmony_ci	  if (!strcmp (symbol_name, looking_for))
508da0c48c4Sopenharmony_ci	    {
509da0c48c4Sopenharmony_ci	      ((void **) arg)[0] = NULL;
510da0c48c4Sopenharmony_ci	      return DWARF_CB_ABORT;
511da0c48c4Sopenharmony_ci	    }
512da0c48c4Sopenharmony_ci	}
513da0c48c4Sopenharmony_ci    }
514da0c48c4Sopenharmony_ci
515da0c48c4Sopenharmony_ci  return DWARF_CB_OK;
516da0c48c4Sopenharmony_ci}
517da0c48c4Sopenharmony_ci
518da0c48c4Sopenharmony_cistatic bool
519da0c48c4Sopenharmony_ciadjust_to_section (const char *name, uintmax_t *addr, Dwfl *dwfl)
520da0c48c4Sopenharmony_ci{
521da0c48c4Sopenharmony_ci  /* It was (section)+offset.  This makes sense if there is
522da0c48c4Sopenharmony_ci     only one module to look in for a section.  */
523da0c48c4Sopenharmony_ci  Dwfl_Module *mod = NULL;
524da0c48c4Sopenharmony_ci  if (dwfl_getmodules (dwfl, &see_one_module, &mod, 0) != 0
525da0c48c4Sopenharmony_ci      || mod == NULL)
526da0c48c4Sopenharmony_ci    error_exit (0, _("Section syntax requires exactly one module"));
527da0c48c4Sopenharmony_ci
528da0c48c4Sopenharmony_ci  int nscn = dwfl_module_relocations (mod);
529da0c48c4Sopenharmony_ci  for (int i = 0; i < nscn; ++i)
530da0c48c4Sopenharmony_ci    {
531da0c48c4Sopenharmony_ci      GElf_Word shndx;
532da0c48c4Sopenharmony_ci      const char *scn = dwfl_module_relocation_info (mod, i, &shndx);
533da0c48c4Sopenharmony_ci      if (unlikely (scn == NULL))
534da0c48c4Sopenharmony_ci	break;
535da0c48c4Sopenharmony_ci      if (!strcmp (scn, name))
536da0c48c4Sopenharmony_ci	{
537da0c48c4Sopenharmony_ci	  /* Found the section.  */
538da0c48c4Sopenharmony_ci	  GElf_Shdr shdr_mem;
539da0c48c4Sopenharmony_ci	  GElf_Addr shdr_bias;
540da0c48c4Sopenharmony_ci	  GElf_Shdr *shdr = gelf_getshdr
541da0c48c4Sopenharmony_ci	    (elf_getscn (dwfl_module_getelf (mod, &shdr_bias), shndx),
542da0c48c4Sopenharmony_ci	     &shdr_mem);
543da0c48c4Sopenharmony_ci	  if (unlikely (shdr == NULL))
544da0c48c4Sopenharmony_ci	    break;
545da0c48c4Sopenharmony_ci
546da0c48c4Sopenharmony_ci	  if (*addr >= shdr->sh_size)
547da0c48c4Sopenharmony_ci	    error (0, 0,
548da0c48c4Sopenharmony_ci		   _("offset %#" PRIxMAX " lies outside"
549da0c48c4Sopenharmony_ci			    " section '%s'"),
550da0c48c4Sopenharmony_ci		   *addr, scn);
551da0c48c4Sopenharmony_ci
552da0c48c4Sopenharmony_ci	  *addr += shdr->sh_addr + shdr_bias;
553da0c48c4Sopenharmony_ci	  return true;
554da0c48c4Sopenharmony_ci	}
555da0c48c4Sopenharmony_ci    }
556da0c48c4Sopenharmony_ci
557da0c48c4Sopenharmony_ci  return false;
558da0c48c4Sopenharmony_ci}
559da0c48c4Sopenharmony_ci
560da0c48c4Sopenharmony_cistatic void
561da0c48c4Sopenharmony_ciprint_src (const char *src, int lineno, int linecol, Dwarf_Die *cu)
562da0c48c4Sopenharmony_ci{
563da0c48c4Sopenharmony_ci  const char *comp_dir = "";
564da0c48c4Sopenharmony_ci  const char *comp_dir_sep = "";
565da0c48c4Sopenharmony_ci
566da0c48c4Sopenharmony_ci  if (only_basenames)
567da0c48c4Sopenharmony_ci    src = basename (src);
568da0c48c4Sopenharmony_ci  else if (use_comp_dir && src[0] != '/')
569da0c48c4Sopenharmony_ci    {
570da0c48c4Sopenharmony_ci      Dwarf_Attribute attr;
571da0c48c4Sopenharmony_ci      comp_dir = dwarf_formstring (dwarf_attr (cu, DW_AT_comp_dir, &attr));
572da0c48c4Sopenharmony_ci      if (comp_dir != NULL)
573da0c48c4Sopenharmony_ci	comp_dir_sep = "/";
574da0c48c4Sopenharmony_ci    }
575da0c48c4Sopenharmony_ci
576da0c48c4Sopenharmony_ci  if (linecol != 0)
577da0c48c4Sopenharmony_ci    printf ("%s%s%s:%d:%d",
578da0c48c4Sopenharmony_ci	    comp_dir, comp_dir_sep, src, lineno, linecol);
579da0c48c4Sopenharmony_ci  else
580da0c48c4Sopenharmony_ci    printf ("%s%s%s:%d",
581da0c48c4Sopenharmony_ci	    comp_dir, comp_dir_sep, src, lineno);
582da0c48c4Sopenharmony_ci}
583da0c48c4Sopenharmony_ci
584da0c48c4Sopenharmony_cistatic int
585da0c48c4Sopenharmony_ciget_addr_width (Dwfl_Module *mod)
586da0c48c4Sopenharmony_ci{
587da0c48c4Sopenharmony_ci  // Try to find the address width if possible.
588da0c48c4Sopenharmony_ci  static int width = 0;
589da0c48c4Sopenharmony_ci  if (width == 0 && mod != NULL)
590da0c48c4Sopenharmony_ci    {
591da0c48c4Sopenharmony_ci      Dwarf_Addr bias;
592da0c48c4Sopenharmony_ci      Elf *elf = dwfl_module_getelf (mod, &bias);
593da0c48c4Sopenharmony_ci      if (elf != NULL)
594da0c48c4Sopenharmony_ci        {
595da0c48c4Sopenharmony_ci	  GElf_Ehdr ehdr_mem;
596da0c48c4Sopenharmony_ci	  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
597da0c48c4Sopenharmony_ci	  if (ehdr != NULL)
598da0c48c4Sopenharmony_ci	    width = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16;
599da0c48c4Sopenharmony_ci	}
600da0c48c4Sopenharmony_ci    }
601da0c48c4Sopenharmony_ci  if (width == 0)
602da0c48c4Sopenharmony_ci    width = 16;
603da0c48c4Sopenharmony_ci
604da0c48c4Sopenharmony_ci  return width;
605da0c48c4Sopenharmony_ci}
606da0c48c4Sopenharmony_ci
607da0c48c4Sopenharmony_cistatic inline void
608da0c48c4Sopenharmony_cishow_note (int (*get) (Dwarf_Line *, bool *),
609da0c48c4Sopenharmony_ci	   Dwarf_Line *info,
610da0c48c4Sopenharmony_ci	   const char *note)
611da0c48c4Sopenharmony_ci{
612da0c48c4Sopenharmony_ci  bool flag;
613da0c48c4Sopenharmony_ci  if ((*get) (info, &flag) == 0 && flag)
614da0c48c4Sopenharmony_ci    fputs (note, stdout);
615da0c48c4Sopenharmony_ci}
616da0c48c4Sopenharmony_ci
617da0c48c4Sopenharmony_cistatic inline void
618da0c48c4Sopenharmony_cishow_int (int (*get) (Dwarf_Line *, unsigned int *),
619da0c48c4Sopenharmony_ci	  Dwarf_Line *info,
620da0c48c4Sopenharmony_ci	  const char *name)
621da0c48c4Sopenharmony_ci{
622da0c48c4Sopenharmony_ci  unsigned int val;
623da0c48c4Sopenharmony_ci  if ((*get) (info, &val) == 0 && val != 0)
624da0c48c4Sopenharmony_ci    printf (" (%s %u)", name, val);
625da0c48c4Sopenharmony_ci}
626da0c48c4Sopenharmony_ci
627da0c48c4Sopenharmony_cistatic int
628da0c48c4Sopenharmony_cihandle_address (const char *string, Dwfl *dwfl)
629da0c48c4Sopenharmony_ci{
630da0c48c4Sopenharmony_ci  char *endp;
631da0c48c4Sopenharmony_ci  uintmax_t addr = strtoumax (string, &endp, 16);
632da0c48c4Sopenharmony_ci  if (endp == string || *endp != '\0')
633da0c48c4Sopenharmony_ci    {
634da0c48c4Sopenharmony_ci      bool parsed = false;
635da0c48c4Sopenharmony_ci      int i, j;
636da0c48c4Sopenharmony_ci      char *name = NULL;
637da0c48c4Sopenharmony_ci      if (sscanf (string, "(%m[^)])%" PRIiMAX "%n", &name, &addr, &i) == 2
638da0c48c4Sopenharmony_ci	  && string[i] == '\0')
639da0c48c4Sopenharmony_ci	parsed = adjust_to_section (name, &addr, dwfl);
640da0c48c4Sopenharmony_ci      switch (sscanf (string, "%m[^-+]%n%" PRIiMAX "%n", &name, &i, &addr, &j))
641da0c48c4Sopenharmony_ci	{
642da0c48c4Sopenharmony_ci	default:
643da0c48c4Sopenharmony_ci	  break;
644da0c48c4Sopenharmony_ci	case 1:
645da0c48c4Sopenharmony_ci	  addr = 0;
646da0c48c4Sopenharmony_ci	  j = i;
647da0c48c4Sopenharmony_ci	  FALLTHROUGH;
648da0c48c4Sopenharmony_ci	case 2:
649da0c48c4Sopenharmony_ci	  if (string[j] != '\0')
650da0c48c4Sopenharmony_ci	    break;
651da0c48c4Sopenharmony_ci
652da0c48c4Sopenharmony_ci	  /* It was symbol[+offset].  */
653da0c48c4Sopenharmony_ci	  GElf_Sym sym;
654da0c48c4Sopenharmony_ci	  GElf_Addr value = 0;
655da0c48c4Sopenharmony_ci	  void *arg[3] = { name, &sym, &value };
656da0c48c4Sopenharmony_ci	  (void) dwfl_getmodules (dwfl, &find_symbol, arg, 0);
657da0c48c4Sopenharmony_ci	  if (arg[0] != NULL)
658da0c48c4Sopenharmony_ci	    error (0, 0, _("cannot find symbol '%s'"), name);
659da0c48c4Sopenharmony_ci	  else
660da0c48c4Sopenharmony_ci	    {
661da0c48c4Sopenharmony_ci	      if (sym.st_size != 0 && addr >= sym.st_size)
662da0c48c4Sopenharmony_ci		error (0, 0,
663da0c48c4Sopenharmony_ci		       _("offset %#" PRIxMAX " lies outside"
664da0c48c4Sopenharmony_ci				" contents of '%s'"),
665da0c48c4Sopenharmony_ci		       addr, name);
666da0c48c4Sopenharmony_ci	      addr += value;
667da0c48c4Sopenharmony_ci	      parsed = true;
668da0c48c4Sopenharmony_ci	    }
669da0c48c4Sopenharmony_ci	  break;
670da0c48c4Sopenharmony_ci	}
671da0c48c4Sopenharmony_ci
672da0c48c4Sopenharmony_ci      free (name);
673da0c48c4Sopenharmony_ci      if (!parsed)
674da0c48c4Sopenharmony_ci	return 1;
675da0c48c4Sopenharmony_ci    }
676da0c48c4Sopenharmony_ci  else if (just_section != NULL
677da0c48c4Sopenharmony_ci	   && !adjust_to_section (just_section, &addr, dwfl))
678da0c48c4Sopenharmony_ci    return 1;
679da0c48c4Sopenharmony_ci
680da0c48c4Sopenharmony_ci  Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr);
681da0c48c4Sopenharmony_ci
682da0c48c4Sopenharmony_ci  if (print_addresses)
683da0c48c4Sopenharmony_ci    {
684da0c48c4Sopenharmony_ci      int width = get_addr_width (mod);
685da0c48c4Sopenharmony_ci      printf ("0x%.*" PRIx64 "%s", width, addr, pretty ? ": " : "\n");
686da0c48c4Sopenharmony_ci    }
687da0c48c4Sopenharmony_ci
688da0c48c4Sopenharmony_ci  if (show_functions)
689da0c48c4Sopenharmony_ci    {
690da0c48c4Sopenharmony_ci      /* First determine the function name.  Use the DWARF information if
691da0c48c4Sopenharmony_ci	 possible.  */
692da0c48c4Sopenharmony_ci      if (! print_dwarf_function (mod, addr) && !show_symbols)
693da0c48c4Sopenharmony_ci	{
694da0c48c4Sopenharmony_ci	  const char *name = dwfl_module_addrname (mod, addr);
695da0c48c4Sopenharmony_ci	  name = name != NULL ? symname (name) : "??";
696da0c48c4Sopenharmony_ci	  printf ("%s%c", name, pretty ? ' ' : '\n');
697da0c48c4Sopenharmony_ci	}
698da0c48c4Sopenharmony_ci    }
699da0c48c4Sopenharmony_ci
700da0c48c4Sopenharmony_ci  if (show_symbols)
701da0c48c4Sopenharmony_ci    print_addrsym (mod, addr);
702da0c48c4Sopenharmony_ci
703da0c48c4Sopenharmony_ci  if ((show_functions || show_symbols) && pretty)
704da0c48c4Sopenharmony_ci    printf ("at ");
705da0c48c4Sopenharmony_ci
706da0c48c4Sopenharmony_ci  Dwfl_Line *line = dwfl_module_getsrc (mod, addr);
707da0c48c4Sopenharmony_ci
708da0c48c4Sopenharmony_ci  const char *src;
709da0c48c4Sopenharmony_ci  int lineno, linecol;
710da0c48c4Sopenharmony_ci
711da0c48c4Sopenharmony_ci  if (line != NULL && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol,
712da0c48c4Sopenharmony_ci					    NULL, NULL)) != NULL)
713da0c48c4Sopenharmony_ci    {
714da0c48c4Sopenharmony_ci      print_src (src, lineno, linecol, dwfl_linecu (line));
715da0c48c4Sopenharmony_ci      if (show_flags)
716da0c48c4Sopenharmony_ci	{
717da0c48c4Sopenharmony_ci	  Dwarf_Addr bias;
718da0c48c4Sopenharmony_ci	  Dwarf_Line *info = dwfl_dwarf_line (line, &bias);
719da0c48c4Sopenharmony_ci	  assert (info != NULL);
720da0c48c4Sopenharmony_ci
721da0c48c4Sopenharmony_ci	  show_note (&dwarf_linebeginstatement, info, " (is_stmt)");
722da0c48c4Sopenharmony_ci	  show_note (&dwarf_lineblock, info, " (basic_block)");
723da0c48c4Sopenharmony_ci	  show_note (&dwarf_lineprologueend, info, " (prologue_end)");
724da0c48c4Sopenharmony_ci	  show_note (&dwarf_lineepiloguebegin, info, " (epilogue_begin)");
725da0c48c4Sopenharmony_ci	  show_int (&dwarf_lineisa, info, "isa");
726da0c48c4Sopenharmony_ci	  show_int (&dwarf_linediscriminator, info, "discriminator");
727da0c48c4Sopenharmony_ci	}
728da0c48c4Sopenharmony_ci      putchar ('\n');
729da0c48c4Sopenharmony_ci    }
730da0c48c4Sopenharmony_ci  else
731da0c48c4Sopenharmony_ci    puts ("??:0");
732da0c48c4Sopenharmony_ci
733da0c48c4Sopenharmony_ci  if (show_inlines)
734da0c48c4Sopenharmony_ci    {
735da0c48c4Sopenharmony_ci      Dwarf_Addr bias = 0;
736da0c48c4Sopenharmony_ci      Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias);
737da0c48c4Sopenharmony_ci
738da0c48c4Sopenharmony_ci      Dwarf_Die *scopes = NULL;
739da0c48c4Sopenharmony_ci      int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes);
740da0c48c4Sopenharmony_ci      if (nscopes < 0)
741da0c48c4Sopenharmony_ci	return 1;
742da0c48c4Sopenharmony_ci
743da0c48c4Sopenharmony_ci      if (nscopes > 0)
744da0c48c4Sopenharmony_ci	{
745da0c48c4Sopenharmony_ci	  Dwarf_Die subroutine;
746da0c48c4Sopenharmony_ci	  Dwarf_Off dieoff = dwarf_dieoffset (&scopes[0]);
747da0c48c4Sopenharmony_ci	  dwarf_offdie (dwfl_module_getdwarf (mod, &bias),
748da0c48c4Sopenharmony_ci			dieoff, &subroutine);
749da0c48c4Sopenharmony_ci	  free (scopes);
750da0c48c4Sopenharmony_ci	  scopes = NULL;
751da0c48c4Sopenharmony_ci
752da0c48c4Sopenharmony_ci	  nscopes = dwarf_getscopes_die (&subroutine, &scopes);
753da0c48c4Sopenharmony_ci	  if (nscopes > 1)
754da0c48c4Sopenharmony_ci	    {
755da0c48c4Sopenharmony_ci	      Dwarf_Die cu;
756da0c48c4Sopenharmony_ci	      Dwarf_Files *files;
757da0c48c4Sopenharmony_ci	      if (dwarf_diecu (&scopes[0], &cu, NULL, NULL) != NULL
758da0c48c4Sopenharmony_ci		  && dwarf_getsrcfiles (cudie, &files, NULL) == 0)
759da0c48c4Sopenharmony_ci		{
760da0c48c4Sopenharmony_ci		  for (int i = 0; i < nscopes - 1; i++)
761da0c48c4Sopenharmony_ci		    {
762da0c48c4Sopenharmony_ci		      Dwarf_Word val;
763da0c48c4Sopenharmony_ci		      Dwarf_Attribute attr;
764da0c48c4Sopenharmony_ci		      Dwarf_Die *die = &scopes[i];
765da0c48c4Sopenharmony_ci		      if (dwarf_tag (die) != DW_TAG_inlined_subroutine)
766da0c48c4Sopenharmony_ci			continue;
767da0c48c4Sopenharmony_ci
768da0c48c4Sopenharmony_ci		      if (pretty)
769da0c48c4Sopenharmony_ci			printf (" (inlined by) ");
770da0c48c4Sopenharmony_ci
771da0c48c4Sopenharmony_ci		      if (show_functions)
772da0c48c4Sopenharmony_ci			{
773da0c48c4Sopenharmony_ci			  /* Search for the parent inline or function.  It
774da0c48c4Sopenharmony_ci			     might not be directly above this inline -- e.g.
775da0c48c4Sopenharmony_ci			     there could be a lexical_block in between.  */
776da0c48c4Sopenharmony_ci			  for (int j = i + 1; j < nscopes; j++)
777da0c48c4Sopenharmony_ci			    {
778da0c48c4Sopenharmony_ci			      Dwarf_Die *parent = &scopes[j];
779da0c48c4Sopenharmony_ci			      int tag = dwarf_tag (parent);
780da0c48c4Sopenharmony_ci			      if (tag == DW_TAG_inlined_subroutine
781da0c48c4Sopenharmony_ci				  || tag == DW_TAG_entry_point
782da0c48c4Sopenharmony_ci				  || tag == DW_TAG_subprogram)
783da0c48c4Sopenharmony_ci				{
784da0c48c4Sopenharmony_ci				  printf ("%s%s",
785da0c48c4Sopenharmony_ci					  symname (get_diename (parent)),
786da0c48c4Sopenharmony_ci					  pretty ? " at " : "\n");
787da0c48c4Sopenharmony_ci				  break;
788da0c48c4Sopenharmony_ci				}
789da0c48c4Sopenharmony_ci			    }
790da0c48c4Sopenharmony_ci			}
791da0c48c4Sopenharmony_ci
792da0c48c4Sopenharmony_ci		      src = NULL;
793da0c48c4Sopenharmony_ci		      lineno = 0;
794da0c48c4Sopenharmony_ci		      linecol = 0;
795da0c48c4Sopenharmony_ci		      if (dwarf_formudata (dwarf_attr (die, DW_AT_call_file,
796da0c48c4Sopenharmony_ci						       &attr), &val) == 0)
797da0c48c4Sopenharmony_ci			src = dwarf_filesrc (files, val, NULL, NULL);
798da0c48c4Sopenharmony_ci
799da0c48c4Sopenharmony_ci		      if (dwarf_formudata (dwarf_attr (die, DW_AT_call_line,
800da0c48c4Sopenharmony_ci						       &attr), &val) == 0)
801da0c48c4Sopenharmony_ci			lineno = val;
802da0c48c4Sopenharmony_ci
803da0c48c4Sopenharmony_ci		      if (dwarf_formudata (dwarf_attr (die, DW_AT_call_column,
804da0c48c4Sopenharmony_ci						       &attr), &val) == 0)
805da0c48c4Sopenharmony_ci			linecol = val;
806da0c48c4Sopenharmony_ci
807da0c48c4Sopenharmony_ci		      if (src != NULL)
808da0c48c4Sopenharmony_ci			{
809da0c48c4Sopenharmony_ci			  print_src (src, lineno, linecol, &cu);
810da0c48c4Sopenharmony_ci			  putchar ('\n');
811da0c48c4Sopenharmony_ci			}
812da0c48c4Sopenharmony_ci		      else
813da0c48c4Sopenharmony_ci			puts ("??:0");
814da0c48c4Sopenharmony_ci		    }
815da0c48c4Sopenharmony_ci		}
816da0c48c4Sopenharmony_ci	    }
817da0c48c4Sopenharmony_ci	}
818da0c48c4Sopenharmony_ci      free (scopes);
819da0c48c4Sopenharmony_ci    }
820da0c48c4Sopenharmony_ci
821da0c48c4Sopenharmony_ci  return 0;
822da0c48c4Sopenharmony_ci}
823da0c48c4Sopenharmony_ci
824da0c48c4Sopenharmony_ci
825da0c48c4Sopenharmony_ci#include "debugpred.h"
826