Blame src/addr2line.c

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