Blame src/addr2line.c

Packit Service 97d2fb
/* Locate source files and line information for given addresses
Packit Service 97d2fb
   Copyright (C) 2005-2010, 2012, 2013, 2015 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of the GNU General Public License as published by
Packit Service 97d2fb
   the Free Software Foundation; either version 3 of the License, or
Packit Service 97d2fb
   (at your option) any later version.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 97d2fb
   GNU General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received a copy of the GNU General Public License
Packit Service 97d2fb
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include <argp.h>
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include <errno.h>
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
#include <inttypes.h>
Packit Service 97d2fb
#include <libdwfl.h>
Packit Service 97d2fb
#include <dwarf.h>
Packit Service 97d2fb
#include <libintl.h>
Packit Service 97d2fb
#include <locale.h>
Packit Service 97d2fb
#include <stdbool.h>
Packit Service 97d2fb
#include <stdio.h>
Packit Service 97d2fb
#include <stdio_ext.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include <system.h>
Packit Service 97d2fb
#include <printversion.h>
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Name and version of program.  */
Packit Service 97d2fb
ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
Packit Service 97d2fb
Packit Service 97d2fb
/* Bug report address.  */
Packit Service 97d2fb
ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Values for the parameters which have no short form.  */
Packit Service 97d2fb
#define OPT_DEMANGLER 0x100
Packit Service 97d2fb
#define OPT_PRETTY 0x101  /* 'p' is already used to select the process.  */
Packit Service 97d2fb
Packit Service 97d2fb
/* Definitions of arguments for argp functions.  */
Packit Service 97d2fb
static const struct argp_option options[] =
Packit Service 97d2fb
{
Packit Service 97d2fb
  { NULL, 0, NULL, 0, N_("Input format options:"), 2 },
Packit Service 97d2fb
  { "section", 'j', "NAME", 0,
Packit Service 97d2fb
    N_("Treat addresses as offsets relative to NAME section."), 0 },
Packit Service 97d2fb
Packit Service 97d2fb
  { NULL, 0, NULL, 0, N_("Output format options:"), 3 },
Packit Service 97d2fb
  { "addresses", 'a', NULL, 0, N_("Print address before each entry"), 0 },
Packit Service 97d2fb
  { "basenames", 's', NULL, 0, N_("Show only base names of source files"), 0 },
Packit Service 97d2fb
  { "absolute", 'A', NULL, 0,
Packit Service 97d2fb
    N_("Show absolute file names using compilation directory"), 0 },
Packit Service 97d2fb
  { "functions", 'f', NULL, 0, N_("Also show function names"), 0 },
Packit Service 97d2fb
  { "symbols", 'S', NULL, 0, N_("Also show symbol or section names"), 0 },
Packit Service 97d2fb
  { "symbols-sections", 'x', NULL, 0, N_("Also show symbol and the section names"), 0 },
Packit Service 97d2fb
  { "flags", 'F', NULL, 0, N_("Also show line table flags"), 0 },
Packit Service 97d2fb
  { "inlines", 'i', NULL, 0,
Packit Service 97d2fb
    N_("Show all source locations that caused inline expansion of subroutines at the address."),
Packit Service 97d2fb
    0 },
Packit Service 97d2fb
  { "demangle", 'C', "ARG", OPTION_ARG_OPTIONAL,
Packit Service 97d2fb
    N_("Show demangled symbols (ARG is always ignored)"), 0 },
Packit Service 97d2fb
  { "pretty-print", OPT_PRETTY, NULL, 0,
Packit Service 97d2fb
    N_("Print all information on one line, and indent inlines"), 0 },
Packit Service 97d2fb
Packit Service 97d2fb
  { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
Packit Service 97d2fb
  /* Unsupported options.  */
Packit Service 97d2fb
  { "target", 'b', "ARG", OPTION_HIDDEN, NULL, 0 },
Packit Service 97d2fb
  { "demangler", OPT_DEMANGLER, "ARG", OPTION_HIDDEN, NULL, 0 },
Packit Service 97d2fb
  { NULL, 0, NULL, 0, NULL, 0 }
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
/* Short description of program.  */
Packit Service 97d2fb
static const char doc[] = N_("\
Packit Service 97d2fb
Locate source files and line information for ADDRs (in a.out by default).");
Packit Service 97d2fb
Packit Service 97d2fb
/* Strings for arguments in help texts.  */
Packit Service 97d2fb
static const char args_doc[] = N_("[ADDR...]");
Packit Service 97d2fb
Packit Service 97d2fb
/* Prototype for option handler.  */
Packit Service 97d2fb
static error_t parse_opt (int key, char *arg, struct argp_state *state);
Packit Service 97d2fb
Packit Service 97d2fb
static struct argp_child argp_children[2]; /* [0] is set in main.  */
Packit Service 97d2fb
Packit Service 97d2fb
/* Data structure to communicate with argp functions.  */
Packit Service 97d2fb
static const struct argp argp =
Packit Service 97d2fb
{
Packit Service 97d2fb
  options, parse_opt, args_doc, doc, argp_children, NULL, NULL
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Handle ADDR.  */
Packit Service 97d2fb
static int handle_address (const char *addr, Dwfl *dwfl);
Packit Service 97d2fb
Packit Service 97d2fb
/* True when we should print the address for each entry.  */
Packit Service 97d2fb
static bool print_addresses;
Packit Service 97d2fb
Packit Service 97d2fb
/* True if only base names of files should be shown.  */
Packit Service 97d2fb
static bool only_basenames;
Packit Service 97d2fb
Packit Service 97d2fb
/* True if absolute file names based on DW_AT_comp_dir should be shown.  */
Packit Service 97d2fb
static bool use_comp_dir;
Packit Service 97d2fb
Packit Service 97d2fb
/* True if line flags should be shown.  */
Packit Service 97d2fb
static bool show_flags;
Packit Service 97d2fb
Packit Service 97d2fb
/* True if function names should be shown.  */
Packit Service 97d2fb
static bool show_functions;
Packit Service 97d2fb
Packit Service 97d2fb
/* True if ELF symbol or section info should be shown.  */
Packit Service 97d2fb
static bool show_symbols;
Packit Service 97d2fb
Packit Service 97d2fb
/* True if section associated with a symbol address should be shown.  */
Packit Service 97d2fb
static bool show_symbol_sections;
Packit Service 97d2fb
Packit Service 97d2fb
/* If non-null, take address parameters as relative to named section.  */
Packit Service 97d2fb
static const char *just_section;
Packit Service 97d2fb
Packit Service 97d2fb
/* True if all inlined subroutines of the current address should be shown.  */
Packit Service 97d2fb
static bool show_inlines;
Packit Service 97d2fb
Packit Service 97d2fb
/* True if all names need to be demangled.  */
Packit Service 97d2fb
static bool demangle;
Packit Service 97d2fb
Packit Service 97d2fb
/* True if all information should be printed on one line.  */
Packit Service 97d2fb
static bool pretty;
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
static size_t demangle_buffer_len = 0;
Packit Service 97d2fb
static char *demangle_buffer = NULL;
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
int
Packit Service 97d2fb
main (int argc, char *argv[])
Packit Service 97d2fb
{
Packit Service 97d2fb
  int remaining;
Packit Service 97d2fb
  int result = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  /* We use no threads here which can interfere with handling a stream.  */
Packit Service 97d2fb
  (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Set locale.  */
Packit Service 97d2fb
  (void) setlocale (LC_ALL, "");
Packit Service 97d2fb
Packit Service 97d2fb
  /* Make sure the message catalog can be found.  */
Packit Service 97d2fb
  (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Initialize the message catalog.  */
Packit Service 97d2fb
  (void) textdomain (PACKAGE_TARNAME);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Parse and process arguments.  This includes opening the modules.  */
Packit Service 97d2fb
  argp_children[0].argp = dwfl_standard_argp ();
Packit Service 97d2fb
  argp_children[0].group = 1;
Packit Service 97d2fb
  Dwfl *dwfl = NULL;
Packit Service 97d2fb
  (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
Packit Service 97d2fb
  assert (dwfl != NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Now handle the addresses.  In case none are given on the command
Packit Service 97d2fb
     line, read from stdin.  */
Packit Service 97d2fb
  if (remaining == argc)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* We use no threads here which can interfere with handling a stream.  */
Packit Service 97d2fb
      (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
Packit Service 97d2fb
Packit Service 97d2fb
      char *buf = NULL;
Packit Service 97d2fb
      size_t len = 0;
Packit Service 97d2fb
      ssize_t chars;
Packit Service 97d2fb
      while (!feof_unlocked (stdin))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if ((chars = getline (&buf, &len, stdin)) < 0)
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (buf[chars - 1] == '\n')
Packit Service 97d2fb
	    buf[chars - 1] = '\0';
Packit Service 97d2fb
Packit Service 97d2fb
	  result = handle_address (buf, dwfl);
Packit Service 97d2fb
	  fflush (stdout);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      free (buf);
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      do
Packit Service 97d2fb
	result = handle_address (argv[remaining], dwfl);
Packit Service 97d2fb
      while (++remaining < argc);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  dwfl_end (dwfl);
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
  free (demangle_buffer);
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Handle program arguments.  */
Packit Service 97d2fb
static error_t
Packit Service 97d2fb
parse_opt (int key, char *arg, struct argp_state *state)
Packit Service 97d2fb
{
Packit Service 97d2fb
  switch (key)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case ARGP_KEY_INIT:
Packit Service 97d2fb
      state->child_inputs[0] = state->input;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'a':
Packit Service 97d2fb
      print_addresses = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'b':
Packit Service 97d2fb
    case 'C':
Packit Service 97d2fb
    case OPT_DEMANGLER:
Packit Service 97d2fb
      demangle = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 's':
Packit Service 97d2fb
      only_basenames = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'A':
Packit Service 97d2fb
      use_comp_dir = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'f':
Packit Service 97d2fb
      show_functions = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'F':
Packit Service 97d2fb
      show_flags = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'S':
Packit Service 97d2fb
      show_symbols = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'x':
Packit Service 97d2fb
      show_symbols = true;
Packit Service 97d2fb
      show_symbol_sections = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'j':
Packit Service 97d2fb
      just_section = arg;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'i':
Packit Service 97d2fb
      show_inlines = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case OPT_PRETTY:
Packit Service 97d2fb
      pretty = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      return ARGP_ERR_UNKNOWN;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static const char *
Packit Service 97d2fb
symname (const char *name)
Packit Service 97d2fb
{
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
  // Require GNU v3 ABI by the "_Z" prefix.
Packit Service 97d2fb
  if (demangle && name[0] == '_' && name[1] == 'Z')
Packit Service 97d2fb
    {
Packit Service 97d2fb
      int status = -1;
Packit Service 97d2fb
      char *dsymname = __cxa_demangle (name, demangle_buffer,
Packit Service 97d2fb
				       &demangle_buffer_len, &status);
Packit Service 97d2fb
      if (status == 0)
Packit Service 97d2fb
	name = demangle_buffer = dsymname;
Packit Service 97d2fb
    }
Packit Service 97d2fb
#endif
Packit Service 97d2fb
  return name;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static const char *
Packit Service 97d2fb
get_diename (Dwarf_Die *die)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwarf_Attribute attr;
Packit Service 97d2fb
  const char *name;
Packit Service 97d2fb
Packit Service 97d2fb
  name = dwarf_formstring (dwarf_attr_integrate (die, DW_AT_MIPS_linkage_name,
Packit Service 97d2fb
						 &attr)
Packit Service 97d2fb
			   ?: dwarf_attr_integrate (die, DW_AT_linkage_name,
Packit Service 97d2fb
						    &attr));
Packit Service 97d2fb
Packit Service 97d2fb
  if (name == NULL)
Packit Service 97d2fb
    name = dwarf_diename (die) ?: "??";
Packit Service 97d2fb
Packit Service 97d2fb
  return name;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwarf_Addr bias = 0;
Packit Service 97d2fb
  Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias);
Packit Service 97d2fb
Packit Service 97d2fb
  Dwarf_Die *scopes;
Packit Service 97d2fb
  int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes);
Packit Service 97d2fb
  if (nscopes <= 0)
Packit Service 97d2fb
    return false;
Packit Service 97d2fb
Packit Service 97d2fb
  bool res = false;
Packit Service 97d2fb
  for (int i = 0; i < nscopes; ++i)
Packit Service 97d2fb
    switch (dwarf_tag (&scopes[i]))
Packit Service 97d2fb
      {
Packit Service 97d2fb
      case DW_TAG_subprogram:
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  const char *name = get_diename (&scopes[i]);
Packit Service 97d2fb
	  if (name == NULL)
Packit Service 97d2fb
	    goto done;
Packit Service 97d2fb
	  printf ("%s%c", symname (name), pretty ? ' ' : '\n');
Packit Service 97d2fb
	  res = true;
Packit Service 97d2fb
	  goto done;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      case DW_TAG_inlined_subroutine:
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  const char *name = get_diename (&scopes[i]);
Packit Service 97d2fb
	  if (name == NULL)
Packit Service 97d2fb
	    goto done;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* When using --pretty-print we only show inlines on their
Packit Service 97d2fb
	     own line.  Just print the first subroutine name.  */
Packit Service 97d2fb
	  if (pretty)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      printf ("%s ", symname (name));
Packit Service 97d2fb
	      res = true;
Packit Service 97d2fb
	      goto done;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    printf ("%s inlined", symname (name));
Packit Service 97d2fb
Packit Service 97d2fb
	  Dwarf_Files *files;
Packit Service 97d2fb
	  if (dwarf_getsrcfiles (cudie, &files, NULL) == 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      Dwarf_Attribute attr_mem;
Packit Service 97d2fb
	      Dwarf_Word val;
Packit Service 97d2fb
	      if (dwarf_formudata (dwarf_attr (&scopes[i],
Packit Service 97d2fb
					       DW_AT_call_file,
Packit Service 97d2fb
					       &attr_mem), &val) == 0)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  const char *file = dwarf_filesrc (files, val, NULL, NULL);
Packit Service 97d2fb
		  unsigned int lineno = 0;
Packit Service 97d2fb
		  unsigned int colno = 0;
Packit Service 97d2fb
		  if (dwarf_formudata (dwarf_attr (&scopes[i],
Packit Service 97d2fb
						   DW_AT_call_line,
Packit Service 97d2fb
						   &attr_mem), &val) == 0)
Packit Service 97d2fb
		    lineno = val;
Packit Service 97d2fb
		  if (dwarf_formudata (dwarf_attr (&scopes[i],
Packit Service 97d2fb
						   DW_AT_call_column,
Packit Service 97d2fb
						   &attr_mem), &val) == 0)
Packit Service 97d2fb
		    colno = val;
Packit Service 97d2fb
Packit Service 97d2fb
		  const char *comp_dir = "";
Packit Service 97d2fb
		  const char *comp_dir_sep = "";
Packit Service 97d2fb
Packit Service 97d2fb
		  if (file == NULL)
Packit Service 97d2fb
		    file = "???";
Packit Service 97d2fb
		  else if (only_basenames)
Packit Service 97d2fb
		    file = basename (file);
Packit Service 97d2fb
		  else if (use_comp_dir && file[0] != '/')
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      const char *const *dirs;
Packit Service 97d2fb
		      size_t ndirs;
Packit Service 97d2fb
		      if (dwarf_getsrcdirs (files, &dirs, &ndirs) == 0
Packit Service 97d2fb
			  && dirs[0] != NULL)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  comp_dir = dirs[0];
Packit Service 97d2fb
			  comp_dir_sep = "/";
Packit Service 97d2fb
			}
Packit Service 97d2fb
		    }
Packit Service 97d2fb
Packit Service 97d2fb
		  if (lineno == 0)
Packit Service 97d2fb
		    printf (" from %s%s%s",
Packit Service 97d2fb
			    comp_dir, comp_dir_sep, file);
Packit Service 97d2fb
		  else if (colno == 0)
Packit Service 97d2fb
		    printf (" at %s%s%s:%u",
Packit Service 97d2fb
			    comp_dir, comp_dir_sep, file, lineno);
Packit Service 97d2fb
		  else
Packit Service 97d2fb
		    printf (" at %s%s%s:%u:%u",
Packit Service 97d2fb
			    comp_dir, comp_dir_sep, file, lineno, colno);
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  printf (" in ");
Packit Service 97d2fb
	  continue;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      }
Packit Service 97d2fb
Packit Service 97d2fb
done:
Packit Service 97d2fb
  free (scopes);
Packit Service 97d2fb
  return res;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
print_addrsym (Dwfl_Module *mod, GElf_Addr addr)
Packit Service 97d2fb
{
Packit Service 97d2fb
  GElf_Sym s;
Packit Service 97d2fb
  GElf_Off off;
Packit Service 97d2fb
  const char *name = dwfl_module_addrinfo (mod, addr, &off, &s,
Packit Service 97d2fb
					   NULL, NULL, NULL);
Packit Service 97d2fb
  if (name == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* No symbol name.  Get a section name instead.  */
Packit Service 97d2fb
      int i = dwfl_module_relocate_address (mod, &addr);
Packit Service 97d2fb
      if (i >= 0)
Packit Service 97d2fb
	name = dwfl_module_relocation_info (mod, i, NULL);
Packit Service 97d2fb
      if (name == NULL)
Packit Service 97d2fb
	printf ("??%c", pretty ? ' ': '\n');
Packit Service 97d2fb
      else
Packit Service 97d2fb
	printf ("(%s)+%#" PRIx64 "%c", name, addr, pretty ? ' ' : '\n');
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      name = symname (name);
Packit Service 97d2fb
      if (off == 0)
Packit Service 97d2fb
	printf ("%s", name);
Packit Service 97d2fb
      else
Packit Service 97d2fb
	printf ("%s+%#" PRIx64 "", name, off);
Packit Service 97d2fb
Packit Service 97d2fb
      // Also show section name for address.
Packit Service 97d2fb
      if (show_symbol_sections)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Dwarf_Addr ebias;
Packit Service 97d2fb
	  Elf_Scn *scn = dwfl_module_address_section (mod, &addr, &ebias);
Packit Service 97d2fb
	  if (scn != NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      GElf_Shdr shdr_mem;
Packit Service 97d2fb
	      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit Service 97d2fb
	      if (shdr != NULL)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  Elf *elf = dwfl_module_getelf (mod, &ebias);
Packit Service 97d2fb
		  size_t shstrndx;
Packit Service 97d2fb
		  if (elf_getshdrstrndx (elf, &shstrndx) >= 0)
Packit Service 97d2fb
		    printf (" (%s)", elf_strptr (elf, shstrndx,
Packit Service 97d2fb
						 shdr->sh_name));
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      printf ("%c", pretty ? ' ' : '\n');
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
see_one_module (Dwfl_Module *mod,
Packit Service 97d2fb
		void **userdata __attribute__ ((unused)),
Packit Service 97d2fb
		const char *name __attribute__ ((unused)),
Packit Service 97d2fb
		Dwarf_Addr start __attribute__ ((unused)),
Packit Service 97d2fb
		void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwfl_Module **result = arg;
Packit Service 97d2fb
  if (*result != NULL)
Packit Service 97d2fb
    return DWARF_CB_ABORT;
Packit Service 97d2fb
  *result = mod;
Packit Service 97d2fb
  return DWARF_CB_OK;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
find_symbol (Dwfl_Module *mod,
Packit Service 97d2fb
	     void **userdata __attribute__ ((unused)),
Packit Service 97d2fb
	     const char *name __attribute__ ((unused)),
Packit Service 97d2fb
	     Dwarf_Addr start __attribute__ ((unused)),
Packit Service 97d2fb
	     void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const char *looking_for = ((void **) arg)[0];
Packit Service 97d2fb
  GElf_Sym *symbol = ((void **) arg)[1];
Packit Service 97d2fb
  GElf_Addr *value = ((void **) arg)[2];
Packit Service 97d2fb
Packit Service 97d2fb
  int n = dwfl_module_getsymtab (mod);
Packit Service 97d2fb
  for (int i = 1; i < n; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      const char *symbol_name = dwfl_module_getsym_info (mod, i, symbol,
Packit Service 97d2fb
							 value, NULL, NULL,
Packit Service 97d2fb
							 NULL);
Packit Service 97d2fb
      if (symbol_name == NULL || symbol_name[0] == '\0')
Packit Service 97d2fb
	continue;
Packit Service 97d2fb
      switch (GELF_ST_TYPE (symbol->st_info))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	case STT_SECTION:
Packit Service 97d2fb
	case STT_FILE:
Packit Service 97d2fb
	case STT_TLS:
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	default:
Packit Service 97d2fb
	  if (!strcmp (symbol_name, looking_for))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      ((void **) arg)[0] = NULL;
Packit Service 97d2fb
	      return DWARF_CB_ABORT;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return DWARF_CB_OK;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static bool
Packit Service 97d2fb
adjust_to_section (const char *name, uintmax_t *addr, Dwfl *dwfl)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* It was (section)+offset.  This makes sense if there is
Packit Service 97d2fb
     only one module to look in for a section.  */
Packit Service 97d2fb
  Dwfl_Module *mod = NULL;
Packit Service 97d2fb
  if (dwfl_getmodules (dwfl, &see_one_module, &mod, 0) != 0
Packit Service 97d2fb
      || mod == NULL)
Packit Service 97d2fb
    error (EXIT_FAILURE, 0, gettext ("Section syntax requires"
Packit Service 97d2fb
				     " exactly one module"));
Packit Service 97d2fb
Packit Service 97d2fb
  int nscn = dwfl_module_relocations (mod);
Packit Service 97d2fb
  for (int i = 0; i < nscn; ++i)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      GElf_Word shndx;
Packit Service 97d2fb
      const char *scn = dwfl_module_relocation_info (mod, i, &shndx);
Packit Service 97d2fb
      if (unlikely (scn == NULL))
Packit Service 97d2fb
	break;
Packit Service 97d2fb
      if (!strcmp (scn, name))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Found the section.  */
Packit Service 97d2fb
	  GElf_Shdr shdr_mem;
Packit Service 97d2fb
	  GElf_Addr shdr_bias;
Packit Service 97d2fb
	  GElf_Shdr *shdr = gelf_getshdr
Packit Service 97d2fb
	    (elf_getscn (dwfl_module_getelf (mod, &shdr_bias), shndx),
Packit Service 97d2fb
	     &shdr_mem);
Packit Service 97d2fb
	  if (unlikely (shdr == NULL))
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
Packit Service 97d2fb
	  if (*addr >= shdr->sh_size)
Packit Service 97d2fb
	    error (0, 0,
Packit Service 97d2fb
		   gettext ("offset %#" PRIxMAX " lies outside"
Packit Service 97d2fb
			    " section '%s'"),
Packit Service 97d2fb
		   *addr, scn);
Packit Service 97d2fb
Packit Service 97d2fb
	  *addr += shdr->sh_addr + shdr_bias;
Packit Service 97d2fb
	  return true;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return false;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
print_src (const char *src, int lineno, int linecol, Dwarf_Die *cu)
Packit Service 97d2fb
{
Packit Service 97d2fb
  const char *comp_dir = "";
Packit Service 97d2fb
  const char *comp_dir_sep = "";
Packit Service 97d2fb
Packit Service 97d2fb
  if (only_basenames)
Packit Service 97d2fb
    src = basename (src);
Packit Service 97d2fb
  else if (use_comp_dir && src[0] != '/')
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Attribute attr;
Packit Service 97d2fb
      comp_dir = dwarf_formstring (dwarf_attr (cu, DW_AT_comp_dir, &attr));
Packit Service 97d2fb
      if (comp_dir != NULL)
Packit Service 97d2fb
	comp_dir_sep = "/";
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (linecol != 0)
Packit Service 97d2fb
    printf ("%s%s%s:%d:%d",
Packit Service 97d2fb
	    comp_dir, comp_dir_sep, src, lineno, linecol);
Packit Service 97d2fb
  else
Packit Service 97d2fb
    printf ("%s%s%s:%d",
Packit Service 97d2fb
	    comp_dir, comp_dir_sep, src, lineno);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
get_addr_width (Dwfl_Module *mod)
Packit Service 97d2fb
{
Packit Service 97d2fb
  // Try to find the address width if possible.
Packit Service 97d2fb
  static int width = 0;
Packit Service 97d2fb
  if (width == 0 && mod != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Addr bias;
Packit Service 97d2fb
      Elf *elf = dwfl_module_getelf (mod, &bias);
Packit Service 97d2fb
      if (elf != NULL)
Packit Service 97d2fb
        {
Packit Service 97d2fb
	  GElf_Ehdr ehdr_mem;
Packit Service 97d2fb
	  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
Packit Service 97d2fb
	  if (ehdr != NULL)
Packit Service 97d2fb
	    width = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  if (width == 0)
Packit Service 97d2fb
    width = 16;
Packit Service 97d2fb
Packit Service 97d2fb
  return width;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
handle_address (const char *string, Dwfl *dwfl)
Packit Service 97d2fb
{
Packit Service 97d2fb
  char *endp;
Packit Service 97d2fb
  uintmax_t addr = strtoumax (string, &endp, 16);
Packit Service 97d2fb
  if (endp == string || *endp != '\0')
Packit Service 97d2fb
    {
Packit Service 97d2fb
      bool parsed = false;
Packit Service 97d2fb
      int i, j;
Packit Service 97d2fb
      char *name = NULL;
Packit Service 97d2fb
      if (sscanf (string, "(%m[^)])%" PRIiMAX "%n", &name, &addr, &i) == 2
Packit Service 97d2fb
	  && string[i] == '\0')
Packit Service 97d2fb
	parsed = adjust_to_section (name, &addr, dwfl);
Packit Service 97d2fb
      switch (sscanf (string, "%m[^-+]%n%" PRIiMAX "%n", &name, &i, &addr, &j))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	default:
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	case 1:
Packit Service 97d2fb
	  addr = 0;
Packit Service 97d2fb
	  j = i;
Packit Service 97d2fb
	  FALLTHROUGH;
Packit Service 97d2fb
	case 2:
Packit Service 97d2fb
	  if (string[j] != '\0')
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* It was symbol[+offset].  */
Packit Service 97d2fb
	  GElf_Sym sym;
Packit Service 97d2fb
	  GElf_Addr value = 0;
Packit Service 97d2fb
	  void *arg[3] = { name, &sym, &value };
Packit Service 97d2fb
	  (void) dwfl_getmodules (dwfl, &find_symbol, arg, 0);
Packit Service 97d2fb
	  if (arg[0] != NULL)
Packit Service 97d2fb
	    error (0, 0, gettext ("cannot find symbol '%s'"), name);
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (sym.st_size != 0 && addr >= sym.st_size)
Packit Service 97d2fb
		error (0, 0,
Packit Service 97d2fb
		       gettext ("offset %#" PRIxMAX " lies outside"
Packit Service 97d2fb
				" contents of '%s'"),
Packit Service 97d2fb
		       addr, name);
Packit Service 97d2fb
	      addr += value;
Packit Service 97d2fb
	      parsed = true;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      free (name);
Packit Service 97d2fb
      if (!parsed)
Packit Service 97d2fb
	return 1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else if (just_section != NULL
Packit Service 97d2fb
	   && !adjust_to_section (just_section, &addr, dwfl))
Packit Service 97d2fb
    return 1;
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr);
Packit Service 97d2fb
Packit Service 97d2fb
  if (print_addresses)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      int width = get_addr_width (mod);
Packit Service 97d2fb
      printf ("0x%.*" PRIx64 "%s", width, addr, pretty ? ": " : "\n");
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (show_functions)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* First determine the function name.  Use the DWARF information if
Packit Service 97d2fb
	 possible.  */
Packit Service 97d2fb
      if (! print_dwarf_function (mod, addr) && !show_symbols)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  const char *name = dwfl_module_addrname (mod, addr);
Packit Service 97d2fb
	  name = name != NULL ? symname (name) : "??";
Packit Service 97d2fb
	  printf ("%s%c", name, pretty ? ' ' : '\n');
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (show_symbols)
Packit Service 97d2fb
    print_addrsym (mod, addr);
Packit Service 97d2fb
Packit Service 97d2fb
  if ((show_functions || show_symbols) && pretty)
Packit Service 97d2fb
    printf ("at ");
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Line *line = dwfl_module_getsrc (mod, addr);
Packit Service 97d2fb
Packit Service 97d2fb
  const char *src;
Packit Service 97d2fb
  int lineno, linecol;
Packit Service 97d2fb
Packit Service 97d2fb
  if (line != NULL && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol,
Packit Service 97d2fb
					    NULL, NULL)) != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      print_src (src, lineno, linecol, dwfl_linecu (line));
Packit Service 97d2fb
      if (show_flags)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Dwarf_Addr bias;
Packit Service 97d2fb
	  Dwarf_Line *info = dwfl_dwarf_line (line, &bias);
Packit Service 97d2fb
	  assert (info != NULL);
Packit Service 97d2fb
Packit Service 97d2fb
	  inline void show (int (*get) (Dwarf_Line *, bool *),
Packit Service 97d2fb
			    const char *note)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    bool flag;
Packit Service 97d2fb
	    if ((*get) (info, &flag) == 0 && flag)
Packit Service 97d2fb
	      fputs (note, stdout);
Packit Service 97d2fb
	  }
Packit Service 97d2fb
	  inline void show_int (int (*get) (Dwarf_Line *, unsigned int *),
Packit Service 97d2fb
				const char *name)
Packit Service 97d2fb
	  {
Packit Service 97d2fb
	    unsigned int val;
Packit Service 97d2fb
	    if ((*get) (info, &val) == 0 && val != 0)
Packit Service 97d2fb
	      printf (" (%s %u)", name, val);
Packit Service 97d2fb
	  }
Packit Service 97d2fb
Packit Service 97d2fb
	  show (&dwarf_linebeginstatement, " (is_stmt)");
Packit Service 97d2fb
	  show (&dwarf_lineblock, " (basic_block)");
Packit Service 97d2fb
	  show (&dwarf_lineprologueend, " (prologue_end)");
Packit Service 97d2fb
	  show (&dwarf_lineepiloguebegin, " (epilogue_begin)");
Packit Service 97d2fb
	  show_int (&dwarf_lineisa, "isa");
Packit Service 97d2fb
	  show_int (&dwarf_linediscriminator, "discriminator");
Packit Service 97d2fb
	}
Packit Service 97d2fb
      putchar ('\n');
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    puts ("??:0");
Packit Service 97d2fb
Packit Service 97d2fb
  if (show_inlines)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Addr bias = 0;
Packit Service 97d2fb
      Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias);
Packit Service 97d2fb
Packit Service 97d2fb
      Dwarf_Die *scopes = NULL;
Packit Service 97d2fb
      int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes);
Packit Service 97d2fb
      if (nscopes < 0)
Packit Service 97d2fb
	return 1;
Packit Service 97d2fb
Packit Service 97d2fb
      if (nscopes > 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Dwarf_Die subroutine;
Packit Service 97d2fb
	  Dwarf_Off dieoff = dwarf_dieoffset (&scopes[0]);
Packit Service 97d2fb
	  dwarf_offdie (dwfl_module_getdwarf (mod, &bias),
Packit Service 97d2fb
			dieoff, &subroutine);
Packit Service 97d2fb
	  free (scopes);
Packit Service 97d2fb
	  scopes = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
	  nscopes = dwarf_getscopes_die (&subroutine, &scopes);
Packit Service 97d2fb
	  if (nscopes > 1)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      Dwarf_Die cu;
Packit Service 97d2fb
	      Dwarf_Files *files;
Packit Service 97d2fb
	      if (dwarf_diecu (&scopes[0], &cu, NULL, NULL) != NULL
Packit Service 97d2fb
		  && dwarf_getsrcfiles (cudie, &files, NULL) == 0)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  for (int i = 0; i < nscopes - 1; i++)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      Dwarf_Word val;
Packit Service 97d2fb
		      Dwarf_Attribute attr;
Packit Service 97d2fb
		      Dwarf_Die *die = &scopes[i];
Packit Service 97d2fb
		      if (dwarf_tag (die) != DW_TAG_inlined_subroutine)
Packit Service 97d2fb
			continue;
Packit Service 97d2fb
Packit Service 97d2fb
		      if (pretty)
Packit Service 97d2fb
			printf (" (inlined by) ");
Packit Service 97d2fb
Packit Service 97d2fb
		      if (show_functions)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  /* Search for the parent inline or function.  It
Packit Service 97d2fb
			     might not be directly above this inline -- e.g.
Packit Service 97d2fb
			     there could be a lexical_block in between.  */
Packit Service 97d2fb
			  for (int j = i + 1; j < nscopes; j++)
Packit Service 97d2fb
			    {
Packit Service 97d2fb
			      Dwarf_Die *parent = &scopes[j];
Packit Service 97d2fb
			      int tag = dwarf_tag (parent);
Packit Service 97d2fb
			      if (tag == DW_TAG_inlined_subroutine
Packit Service 97d2fb
				  || tag == DW_TAG_entry_point
Packit Service 97d2fb
				  || tag == DW_TAG_subprogram)
Packit Service 97d2fb
				{
Packit Service 97d2fb
				  printf ("%s%s",
Packit Service 97d2fb
					  symname (get_diename (parent)),
Packit Service 97d2fb
					  pretty ? " at " : "\n");
Packit Service 97d2fb
				  break;
Packit Service 97d2fb
				}
Packit Service 97d2fb
			    }
Packit Service 97d2fb
			}
Packit Service 97d2fb
Packit Service 97d2fb
		      src = NULL;
Packit Service 97d2fb
		      lineno = 0;
Packit Service 97d2fb
		      linecol = 0;
Packit Service 97d2fb
		      if (dwarf_formudata (dwarf_attr (die, DW_AT_call_file,
Packit Service 97d2fb
						       &attr), &val) == 0)
Packit Service 97d2fb
			src = dwarf_filesrc (files, val, NULL, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
		      if (dwarf_formudata (dwarf_attr (die, DW_AT_call_line,
Packit Service 97d2fb
						       &attr), &val) == 0)
Packit Service 97d2fb
			lineno = val;
Packit Service 97d2fb
Packit Service 97d2fb
		      if (dwarf_formudata (dwarf_attr (die, DW_AT_call_column,
Packit Service 97d2fb
						       &attr), &val) == 0)
Packit Service 97d2fb
			linecol = val;
Packit Service 97d2fb
Packit Service 97d2fb
		      if (src != NULL)
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  print_src (src, lineno, linecol, &cu);
Packit Service 97d2fb
			  putchar ('\n');
Packit Service 97d2fb
			}
Packit Service 97d2fb
		      else
Packit Service 97d2fb
			puts ("??:0");
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      free (scopes);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
#include "debugpred.h"