Blame src/stack.c

Packit Service 97d2fb
/* Unwinding of frames like gstack/pstack.
Packit Service 97d2fb
   Copyright (C) 2013-2014 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
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
#include <config.h>
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include <argp.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <inttypes.h>
Packit Service 97d2fb
#include <stdio.h>
Packit Service 97d2fb
#include <stdio_ext.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
#include <locale.h>
Packit Service 97d2fb
#include <fcntl.h>
Packit Service 97d2fb
#include ELFUTILS_HEADER(dwfl)
Packit Service 97d2fb
Packit Service 97d2fb
#include <dwarf.h>
Packit Service 97d2fb
#include <system.h>
Packit Service 97d2fb
#include <printversion.h>
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
/* non-printable argp options.  */
Packit Service 97d2fb
#define OPT_DEBUGINFO	0x100
Packit Service 97d2fb
#define OPT_COREFILE	0x101
Packit Service 97d2fb
Packit Service 97d2fb
static bool show_activation = false;
Packit Service 97d2fb
static bool show_module = false;
Packit Service 97d2fb
static bool show_build_id = false;
Packit Service 97d2fb
static bool show_source = false;
Packit Service 97d2fb
static bool show_one_tid = false;
Packit Service 97d2fb
static bool show_quiet = false;
Packit Service 97d2fb
static bool show_raw = false;
Packit Service 97d2fb
static bool show_modules = false;
Packit Service 97d2fb
static bool show_debugname = false;
Packit Service 97d2fb
static bool show_inlines = false;
Packit Service 97d2fb
Packit Service 97d2fb
static int maxframes = 256;
Packit Service 97d2fb
Packit Service 97d2fb
struct frame
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwarf_Addr pc;
Packit Service 97d2fb
  bool isactivation;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
struct frames
Packit Service 97d2fb
{
Packit Service 97d2fb
  int frames;
Packit Service 97d2fb
  int allocated;
Packit Service 97d2fb
  struct frame *frame;
Packit Service 97d2fb
};
Packit Service 97d2fb
Packit Service 97d2fb
static Dwfl *dwfl = NULL;
Packit Service 97d2fb
static pid_t pid = 0;
Packit Service 97d2fb
static int core_fd = -1;
Packit Service 97d2fb
static Elf *core = NULL;
Packit Service 97d2fb
static const char *exec = NULL;
Packit Service 97d2fb
static char *debuginfo_path = NULL;
Packit Service 97d2fb
Packit Service 97d2fb
static const Dwfl_Callbacks proc_callbacks =
Packit Service 97d2fb
  {
Packit Service 97d2fb
    .find_elf = dwfl_linux_proc_find_elf,
Packit Service 97d2fb
    .find_debuginfo = dwfl_standard_find_debuginfo,
Packit Service 97d2fb
    .debuginfo_path = &debuginfo_path,
Packit Service 97d2fb
  };
Packit Service 97d2fb
Packit Service 97d2fb
static const Dwfl_Callbacks core_callbacks =
Packit Service 97d2fb
  {
Packit Service 97d2fb
    .find_elf = dwfl_build_id_find_elf,
Packit Service 97d2fb
    .find_debuginfo = dwfl_standard_find_debuginfo,
Packit Service 97d2fb
    .debuginfo_path = &debuginfo_path,
Packit Service 97d2fb
  };
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
/* Whether any frames have been shown at all.  Determines exit status.  */
Packit Service 97d2fb
static bool frames_shown = false;
Packit Service 97d2fb
Packit Service 97d2fb
/* Program exit codes. All frames shown without any errors is GOOD.
Packit Service 97d2fb
   Some frames shown with some non-fatal errors is an ERROR.  A fatal
Packit Service 97d2fb
   error or no frames shown at all is BAD.  A command line USAGE exit
Packit Service 97d2fb
   is generated by argp_error.  */
Packit Service 97d2fb
#define EXIT_OK     0
Packit Service 97d2fb
#define EXIT_ERROR  1
Packit Service 97d2fb
#define EXIT_BAD    2
Packit Service 97d2fb
#define EXIT_USAGE 64
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 wide if possible.
Packit Service 97d2fb
  static int width = 0;
Packit Service 97d2fb
  if (width == 0 && mod)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Addr bias;
Packit Service 97d2fb
      Elf *elf = dwfl_module_getelf (mod, &bias);
Packit Service 97d2fb
      if (elf)
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)
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
module_callback (Dwfl_Module *mod, void **userdata __attribute__((unused)),
Packit Service 97d2fb
		 const char *name, Dwarf_Addr start,
Packit Service 97d2fb
		 void *arg __attribute__((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Forces resolving of main elf and debug files. */
Packit Service 97d2fb
  Dwarf_Addr bias;
Packit Service 97d2fb
  Elf *elf = dwfl_module_getelf (mod, &bias);
Packit Service 97d2fb
  Dwarf *dwarf = dwfl_module_getdwarf (mod, &bias);
Packit Service 97d2fb
Packit Service 97d2fb
  Dwarf_Addr end;
Packit Service 97d2fb
  const char *mainfile;
Packit Service 97d2fb
  const char *debugfile;
Packit Service 97d2fb
  const char *modname = dwfl_module_info (mod, NULL, NULL, &end, NULL,
Packit Service 97d2fb
                                          NULL, &mainfile, &debugfile);
Packit Service 97d2fb
  if (modname == NULL || strcmp (modname, name) != 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      end = start + 1;
Packit Service 97d2fb
      mainfile = NULL;
Packit Service 97d2fb
      debugfile = NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  int width = get_addr_width (mod);
Packit Service 97d2fb
  printf ("0x%0*" PRIx64 "-0x%0*" PRIx64 " %s\n",
Packit Service 97d2fb
	  width, start, width, end, basename (name));
Packit Service 97d2fb
Packit Service 97d2fb
  const unsigned char *id;
Packit Service 97d2fb
  GElf_Addr id_vaddr;
Packit Service 97d2fb
  int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
Packit Service 97d2fb
  if (id_len > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      printf ("  [");
Packit Service 97d2fb
      do
Packit Service 97d2fb
	printf ("%02" PRIx8, *id++);
Packit Service 97d2fb
      while (--id_len > 0);
Packit Service 97d2fb
      printf ("]\n");
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (elf != NULL)
Packit Service 97d2fb
    printf ("  %s\n", mainfile != NULL ? mainfile : "-");
Packit Service 97d2fb
  if (dwarf != NULL)
Packit Service 97d2fb
    printf ("  %s\n", debugfile != NULL ? debugfile : "-");
Packit Service 97d2fb
Packit Service 97d2fb
  return DWARF_CB_OK;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
frame_callback (Dwfl_Frame *state, void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct frames *frames = (struct frames *) arg;
Packit Service 97d2fb
  int nr = frames->frames;
Packit Service 97d2fb
  if (! dwfl_frame_pc (state, &frames->frame[nr].pc,
Packit Service 97d2fb
		       &frames->frame[nr].isactivation))
Packit Service 97d2fb
    return -1;
Packit Service 97d2fb
Packit Service 97d2fb
  frames->frames++;
Packit Service 97d2fb
  if (frames->frames == maxframes)
Packit Service 97d2fb
    return DWARF_CB_ABORT;
Packit Service 97d2fb
Packit Service 97d2fb
  if (frames->frames == frames->allocated)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      frames->allocated *= 2;
Packit Service 97d2fb
      frames->frame = realloc (frames->frame,
Packit Service 97d2fb
			       sizeof (struct frame) * frames->allocated);
Packit Service 97d2fb
      if (frames->frame == NULL)
Packit Service 97d2fb
	error (EXIT_BAD, errno, "realloc frames.frame");
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return DWARF_CB_OK;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static const char*
Packit Service 97d2fb
die_name (Dwarf_Die *die)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwarf_Attribute attr;
Packit Service 97d2fb
  const char *name;
Packit Service 97d2fb
  name = dwarf_formstring (dwarf_attr_integrate (die,
Packit Service 97d2fb
						 DW_AT_MIPS_linkage_name,
Packit Service 97d2fb
						 &attr)
Packit Service 97d2fb
			   ?: dwarf_attr_integrate (die,
Packit Service 97d2fb
						    DW_AT_linkage_name,
Packit Service 97d2fb
						    &attr));
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 void
Packit Service 97d2fb
print_frame (int nr, Dwarf_Addr pc, bool isactivation,
Packit Service 97d2fb
	     Dwarf_Addr pc_adjusted, Dwfl_Module *mod,
Packit Service 97d2fb
	     const char *symname, Dwarf_Die *cudie,
Packit Service 97d2fb
	     Dwarf_Die *die)
Packit Service 97d2fb
{
Packit Service 97d2fb
  int width = get_addr_width (mod);
Packit Service 97d2fb
  printf ("#%-2u 0x%0*" PRIx64, nr, width, (uint64_t) pc);
Packit Service 97d2fb
Packit Service 97d2fb
  if (show_activation)
Packit Service 97d2fb
    printf ("%4s", ! isactivation ? "- 1" : "");
Packit Service 97d2fb
Packit Service 97d2fb
  if (symname != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
#ifdef USE_DEMANGLE
Packit Service 97d2fb
      // Require GNU v3 ABI by the "_Z" prefix.
Packit Service 97d2fb
      if (! show_raw && symname[0] == '_' && symname[1] == 'Z')
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int status = -1;
Packit Service 97d2fb
	  char *dsymname = __cxa_demangle (symname, demangle_buffer,
Packit Service 97d2fb
					   &demangle_buffer_len, &status);
Packit Service 97d2fb
	  if (status == 0)
Packit Service 97d2fb
	    symname = demangle_buffer = dsymname;
Packit Service 97d2fb
	}
Packit Service 97d2fb
#endif
Packit Service 97d2fb
      printf (" %s", symname);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  const char* fname;
Packit Service 97d2fb
  Dwarf_Addr start;
Packit Service 97d2fb
  fname = dwfl_module_info(mod, NULL, &start,
Packit Service 97d2fb
			   NULL, NULL, NULL, NULL, NULL);
Packit Service 97d2fb
  if (show_module)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (fname != NULL)
Packit Service 97d2fb
	printf (" - %s", fname);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (show_build_id)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      const unsigned char *id;
Packit Service 97d2fb
      GElf_Addr id_vaddr;
Packit Service 97d2fb
      int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
Packit Service 97d2fb
      if (id_len > 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  printf ("\n    [");
Packit Service 97d2fb
	  do
Packit Service 97d2fb
	    printf ("%02" PRIx8, *id++);
Packit Service 97d2fb
	  while (--id_len > 0);
Packit Service 97d2fb
	  printf ("]@0x%0" PRIx64 "+0x%" PRIx64,
Packit Service 97d2fb
		  start, pc_adjusted - start);
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (show_source)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      int line, col;
Packit Service 97d2fb
      const char* sname;
Packit Service 97d2fb
      line = col = -1;
Packit Service 97d2fb
      sname = NULL;
Packit Service 97d2fb
      if (die != NULL)
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;
Packit Service 97d2fb
	      Dwarf_Word val;
Packit Service 97d2fb
	      if (dwarf_formudata (dwarf_attr (die, DW_AT_call_file, &attr),
Packit Service 97d2fb
				   &val) == 0)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  sname = dwarf_filesrc (files, val, NULL, NULL);
Packit Service 97d2fb
		  if (dwarf_formudata (dwarf_attr (die, DW_AT_call_line,
Packit Service 97d2fb
						   &attr), &val) == 0)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      line = val;
Packit Service 97d2fb
		      if (dwarf_formudata (dwarf_attr (die, DW_AT_call_column,
Packit Service 97d2fb
						       &attr), &val) == 0)
Packit Service 97d2fb
			col = val;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Dwfl_Line *lineobj = dwfl_module_getsrc(mod, pc_adjusted);
Packit Service 97d2fb
	  if (lineobj)
Packit Service 97d2fb
	    sname = dwfl_lineinfo (lineobj, NULL, &line, &col, NULL, NULL);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (sname != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  printf ("\n    %s", sname);
Packit Service 97d2fb
	  if (line > 0)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      printf (":%d", line);
Packit Service 97d2fb
	      if (col > 0)
Packit Service 97d2fb
		printf (":%d", col);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  printf ("\n");
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
print_inline_frames (int *nr, Dwarf_Addr pc, bool isactivation,
Packit Service 97d2fb
		     Dwarf_Addr pc_adjusted, Dwfl_Module *mod,
Packit Service 97d2fb
		     const char *symname, Dwarf_Die *cudie, Dwarf_Die *die)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwarf_Die *scopes = NULL;
Packit Service 97d2fb
  int nscopes = dwarf_getscopes_die (die, &scopes);
Packit Service 97d2fb
  if (nscopes > 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* scopes[0] == die, the lowest level, for which we already have
Packit Service 97d2fb
	 the name.  This is the actual source location where it
Packit Service 97d2fb
	 happened.  */
Packit Service 97d2fb
      print_frame ((*nr)++, pc, isactivation, pc_adjusted, mod, symname,
Packit Service 97d2fb
		   NULL, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
      /* last_scope is the source location where the next frame/function
Packit Service 97d2fb
	 call was done. */
Packit Service 97d2fb
      Dwarf_Die *last_scope = &scopes[0];
Packit Service 97d2fb
      for (int i = 1; i < nscopes && (maxframes == 0 || *nr < maxframes); i++)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Dwarf_Die *scope = &scopes[i];
Packit Service 97d2fb
	  int tag = dwarf_tag (scope);
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
	    continue;
Packit Service 97d2fb
Packit Service 97d2fb
	  symname = die_name (scope);
Packit Service 97d2fb
	  print_frame ((*nr)++, pc, isactivation, pc_adjusted, mod, symname,
Packit Service 97d2fb
		       cudie, last_scope);
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Found the "top-level" in which everything was inlined?  */
Packit Service 97d2fb
	  if (tag == DW_TAG_subprogram)
Packit Service 97d2fb
	    break;
Packit Service 97d2fb
Packit Service 97d2fb
	  last_scope = scope;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  free (scopes);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
print_frames (struct frames *frames, pid_t tid, int dwflerr, const char *what)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (frames->frames > 0)
Packit Service 97d2fb
    frames_shown = true;
Packit Service 97d2fb
Packit Service 97d2fb
  printf ("TID %lld:\n", (long long) tid);
Packit Service 97d2fb
  int frame_nr = 0;
Packit Service 97d2fb
  for (int nr = 0; nr < frames->frames && (maxframes == 0
Packit Service 97d2fb
					   || frame_nr < maxframes); nr++)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwarf_Addr pc = frames->frame[nr].pc;
Packit Service 97d2fb
      bool isactivation = frames->frame[nr].isactivation;
Packit Service 97d2fb
      Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
Packit Service 97d2fb
Packit Service 97d2fb
      /* Get PC->SYMNAME.  */
Packit Service 97d2fb
      Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
Packit Service 97d2fb
      const char *symname = NULL;
Packit Service 97d2fb
      Dwarf_Die die_mem;
Packit Service 97d2fb
      Dwarf_Die *die = NULL;
Packit Service 97d2fb
      Dwarf_Die *cudie = NULL;
Packit Service 97d2fb
      if (mod && ! show_quiet)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (show_debugname)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      Dwarf_Addr bias = 0;
Packit Service 97d2fb
	      Dwarf_Die *scopes = NULL;
Packit Service 97d2fb
	      cudie = dwfl_module_addrdie (mod, pc_adjusted, &bias);
Packit Service 97d2fb
	      int nscopes = dwarf_getscopes (cudie, pc_adjusted - bias,
Packit Service 97d2fb
					     &scopes);
Packit Service 97d2fb
Packit Service 97d2fb
	      /* Find the first function-like DIE with a name in scope.  */
Packit Service 97d2fb
	      for (int i = 0; symname == NULL && i < nscopes; i++)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  Dwarf_Die *scope = &scopes[i];
Packit Service 97d2fb
		  int tag = dwarf_tag (scope);
Packit Service 97d2fb
		  if (tag == DW_TAG_subprogram
Packit Service 97d2fb
		      || tag == DW_TAG_inlined_subroutine
Packit Service 97d2fb
		      || tag == DW_TAG_entry_point)
Packit Service 97d2fb
		    symname = die_name (scope);
Packit Service 97d2fb
Packit Service 97d2fb
		  if (symname != NULL)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      die_mem = *scope;
Packit Service 97d2fb
		      die = &die_mem;
Packit Service 97d2fb
		    }
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      free (scopes);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  if (symname == NULL)
Packit Service 97d2fb
	    symname = dwfl_module_addrname (mod, pc_adjusted);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (show_inlines && die != NULL)
Packit Service 97d2fb
	print_inline_frames (&frame_nr, pc, isactivation, pc_adjusted, mod,
Packit Service 97d2fb
			     symname, cudie, die);
Packit Service 97d2fb
      else
Packit Service 97d2fb
	print_frame (frame_nr++, pc, isactivation, pc_adjusted, mod, symname,
Packit Service 97d2fb
		     NULL, NULL);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (frames->frames > 0 && frame_nr == maxframes)
Packit Service 97d2fb
    error (0, 0, "tid %lld: shown max number of frames "
Packit Service 97d2fb
	   "(%d, use -n 0 for unlimited)", (long long) tid, maxframes);
Packit Service 97d2fb
  else if (dwflerr != 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (frames->frames > 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  unsigned nr = frames->frames - 1;
Packit Service 97d2fb
	  Dwarf_Addr pc = frames->frame[nr].pc;
Packit Service 97d2fb
	  bool isactivation = frames->frame[nr].isactivation;
Packit Service 97d2fb
	  Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
Packit Service 97d2fb
	  Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
Packit Service 97d2fb
	  const char *mainfile = NULL;
Packit Service 97d2fb
	  const char *modname = dwfl_module_info (mod, NULL, NULL, NULL, NULL,
Packit Service 97d2fb
						  NULL, &mainfile, NULL);
Packit Service 97d2fb
	  if (modname == NULL || modname[0] == '\0')
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      if (mainfile != NULL)
Packit Service 97d2fb
		modname = mainfile;
Packit Service 97d2fb
	      else
Packit Service 97d2fb
		modname = "<unknown>";
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  error (0, 0, "%s tid %lld at 0x%" PRIx64 " in %s: %s", what,
Packit Service 97d2fb
		 (long long) tid, pc_adjusted, modname, dwfl_errmsg (dwflerr));
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	error (0, 0, "%s tid %lld: %s", what, (long long) tid,
Packit Service 97d2fb
	       dwfl_errmsg (dwflerr));
Packit Service 97d2fb
    }
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static int
Packit Service 97d2fb
thread_callback (Dwfl_Thread *thread, void *thread_arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  struct frames *frames = (struct frames *) thread_arg;
Packit Service 97d2fb
  pid_t tid = dwfl_thread_tid (thread);
Packit Service 97d2fb
  int err = 0;
Packit Service 97d2fb
  frames->frames = 0;
Packit Service 97d2fb
  switch (dwfl_thread_getframes (thread, frame_callback, thread_arg))
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case DWARF_CB_OK:
Packit Service 97d2fb
    case DWARF_CB_ABORT:
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    case -1:
Packit Service 97d2fb
      err = dwfl_errno ();
Packit Service 97d2fb
      break;
Packit Service 97d2fb
    default:
Packit Service 97d2fb
      abort ();
Packit Service 97d2fb
    }
Packit Service 97d2fb
  print_frames (frames, tid, err, "dwfl_thread_getframes");
Packit Service 97d2fb
  return DWARF_CB_OK;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static error_t
Packit Service 97d2fb
parse_opt (int key, char *arg __attribute__ ((unused)),
Packit Service 97d2fb
	   struct argp_state *state)
Packit Service 97d2fb
{
Packit Service 97d2fb
  switch (key)
Packit Service 97d2fb
    {
Packit Service 97d2fb
    case 'p':
Packit Service 97d2fb
      pid = atoi (arg);
Packit Service 97d2fb
      if (pid == 0)
Packit Service 97d2fb
	argp_error (state, N_("-p PID should be a positive process id."));
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case OPT_COREFILE:
Packit Service 97d2fb
      core_fd = open (arg, O_RDONLY);
Packit Service 97d2fb
      if (core_fd < 0)
Packit Service 97d2fb
	error (EXIT_BAD, errno, N_("Cannot open core file '%s'"), arg);
Packit Service 97d2fb
      elf_version (EV_CURRENT);
Packit Service 97d2fb
      core = elf_begin (core_fd, ELF_C_READ_MMAP, NULL);
Packit Service 97d2fb
      if (core == NULL)
Packit Service 97d2fb
	error (EXIT_BAD, 0, "core '%s' elf_begin: %s", arg, elf_errmsg(-1));
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'e':
Packit Service 97d2fb
      exec = arg;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case OPT_DEBUGINFO:
Packit Service 97d2fb
      debuginfo_path = arg;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'm':
Packit Service 97d2fb
      show_module = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 's':
Packit Service 97d2fb
      show_source = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'a':
Packit Service 97d2fb
      show_activation = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'd':
Packit Service 97d2fb
      show_debugname = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'i':
Packit Service 97d2fb
      show_inlines = show_debugname = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'v':
Packit Service 97d2fb
      show_activation = show_source = show_module = show_debugname = true;
Packit Service 97d2fb
      show_inlines = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'b':
Packit Service 97d2fb
      show_build_id = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'q':
Packit Service 97d2fb
      show_quiet = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'r':
Packit Service 97d2fb
      show_raw = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case '1':
Packit Service 97d2fb
      show_one_tid = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'n':
Packit Service 97d2fb
      maxframes = atoi (arg);
Packit Service 97d2fb
      if (maxframes < 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  argp_error (state, N_("-n MAXFRAMES should be 0 or higher."));
Packit Service 97d2fb
	  return EINVAL;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case 'l':
Packit Service 97d2fb
      show_modules = true;
Packit Service 97d2fb
      break;
Packit Service 97d2fb
Packit Service 97d2fb
    case ARGP_KEY_END:
Packit Service 97d2fb
      if (core == NULL && exec != NULL)
Packit Service 97d2fb
	argp_error (state,
Packit Service 97d2fb
		    N_("-e EXEC needs a core given by --core."));
Packit Service 97d2fb
Packit Service 97d2fb
      if (pid == 0 && show_one_tid == true)
Packit Service 97d2fb
	argp_error (state,
Packit Service 97d2fb
		    N_("-1 needs a thread id given by -p."));
Packit Service 97d2fb
Packit Service 97d2fb
      if ((pid == 0 && core == NULL) || (pid != 0 && core != NULL))
Packit Service 97d2fb
	argp_error (state,
Packit Service 97d2fb
		    N_("One of -p PID or --core COREFILE should be given."));
Packit Service 97d2fb
Packit Service 97d2fb
      if (pid != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  dwfl = dwfl_begin (&proc_callbacks);
Packit Service 97d2fb
	  if (dwfl == NULL)
Packit Service 97d2fb
	    error (EXIT_BAD, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
	  int err = dwfl_linux_proc_report (dwfl, pid);
Packit Service 97d2fb
	  if (err < 0)
Packit Service 97d2fb
	    error (EXIT_BAD, 0, "dwfl_linux_proc_report pid %lld: %s",
Packit Service 97d2fb
		   (long long) pid, dwfl_errmsg (-1));
Packit Service 97d2fb
	  else if (err > 0)
Packit Service 97d2fb
	    error (EXIT_BAD, err, "dwfl_linux_proc_report pid %lld",
Packit Service 97d2fb
		   (long long) pid);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (core != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  dwfl = dwfl_begin (&core_callbacks);
Packit Service 97d2fb
	  if (dwfl == NULL)
Packit Service 97d2fb
	    error (EXIT_BAD, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
	  if (dwfl_core_file_report (dwfl, core, exec) < 0)
Packit Service 97d2fb
	    error (EXIT_BAD, 0, "dwfl_core_file_report: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (dwfl_report_end (dwfl, NULL, NULL) != 0)
Packit Service 97d2fb
	error (EXIT_BAD, 0, "dwfl_report_end: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
Packit Service 97d2fb
      if (pid != 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int err = dwfl_linux_proc_attach (dwfl, pid, false);
Packit Service 97d2fb
	  if (err < 0)
Packit Service 97d2fb
	    error (EXIT_BAD, 0, "dwfl_linux_proc_attach pid %lld: %s",
Packit Service 97d2fb
		   (long long) pid, dwfl_errmsg (-1));
Packit Service 97d2fb
	  else if (err > 0)
Packit Service 97d2fb
	    error (EXIT_BAD, err, "dwfl_linux_proc_attach pid %lld",
Packit Service 97d2fb
		   (long long) pid);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (core != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (dwfl_core_file_attach (dwfl, core) < 0)
Packit Service 97d2fb
	    error (EXIT_BAD, 0, "dwfl_core_file_attach: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Makes sure we are properly attached.  */
Packit Service 97d2fb
      if (dwfl_pid (dwfl) < 0)
Packit Service 97d2fb
	error (EXIT_BAD, 0, "dwfl_pid: %s\n", dwfl_errmsg (-1));
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
int
Packit Service 97d2fb
main (int argc, char **argv)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* We use no threads here which can interfere with handling a stream.  */
Packit Service 97d2fb
  __fsetlocking (stdin, FSETLOCKING_BYCALLER);
Packit Service 97d2fb
  __fsetlocking (stdout, FSETLOCKING_BYCALLER);
Packit Service 97d2fb
  __fsetlocking (stderr, FSETLOCKING_BYCALLER);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Set locale.  */
Packit Service 97d2fb
  (void) setlocale (LC_ALL, "");
Packit Service 97d2fb
Packit Service 97d2fb
  const struct argp_option options[] =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      { NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
Packit Service 97d2fb
      { "pid", 'p', "PID", 0,
Packit Service 97d2fb
	N_("Show stack of process PID"), 0 },
Packit Service 97d2fb
      { "core", OPT_COREFILE, "COREFILE", 0,
Packit Service 97d2fb
	N_("Show stack found in COREFILE"), 0 },
Packit Service 97d2fb
      {  "executable", 'e', "EXEC", 0, N_("(optional) EXECUTABLE that produced COREFILE"), 0 },
Packit Service 97d2fb
      { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
Packit Service 97d2fb
	N_("Search path for separate debuginfo files"), 0 },
Packit Service 97d2fb
Packit Service 97d2fb
      { NULL, 0, NULL, 0, N_("Output selection options:"), 0 },
Packit Service 97d2fb
      { "activation",  'a', NULL, 0,
Packit Service 97d2fb
	N_("Additionally show frame activation"), 0 },
Packit Service 97d2fb
      { "debugname",  'd', NULL, 0,
Packit Service 97d2fb
	N_("Additionally try to lookup DWARF debuginfo name for frame address"),
Packit Service 97d2fb
	0 },
Packit Service 97d2fb
      { "inlines",  'i', NULL, 0,
Packit Service 97d2fb
	N_("Additionally show inlined function frames using DWARF debuginfo if available (implies -d)"), 0 },
Packit Service 97d2fb
      { "module",  'm', NULL, 0,
Packit Service 97d2fb
	N_("Additionally show module file information"), 0 },
Packit Service 97d2fb
      { "source",  's', NULL, 0,
Packit Service 97d2fb
	N_("Additionally show source file information"), 0 },
Packit Service 97d2fb
      { "verbose", 'v', NULL, 0,
Packit Service 97d2fb
	N_("Show all additional information (activation, debugname, inlines, module and source)"), 0 },
Packit Service 97d2fb
      { "quiet", 'q', NULL, 0,
Packit Service 97d2fb
	N_("Do not resolve address to function symbol name"), 0 },
Packit Service 97d2fb
      { "raw", 'r', NULL, 0,
Packit Service 97d2fb
	N_("Show raw function symbol names, do not try to demangle names"), 0 },
Packit Service 97d2fb
      { "build-id",  'b', NULL, 0,
Packit Service 97d2fb
	N_("Show module build-id, load address and pc offset"), 0 },
Packit Service 97d2fb
      { NULL, '1', NULL, 0,
Packit Service 97d2fb
	N_("Show the backtrace of only one thread"), 0 },
Packit Service 97d2fb
      { NULL, 'n', "MAXFRAMES", 0,
Packit Service 97d2fb
	N_("Show at most MAXFRAMES per thread (default 256, use 0 for unlimited)"), 0 },
Packit Service 97d2fb
      { "list-modules", 'l', NULL, 0,
Packit Service 97d2fb
	N_("Show module memory map with build-id, elf and debug files detected"), 0 },
Packit Service 97d2fb
      { NULL, 0, NULL, 0, NULL, 0 }
Packit Service 97d2fb
    };
Packit Service 97d2fb
Packit Service 97d2fb
  const struct argp argp =
Packit Service 97d2fb
    {
Packit Service 97d2fb
      .options = options,
Packit Service 97d2fb
      .parser = parse_opt,
Packit Service 97d2fb
      .doc = N_("Print a stack for each thread in a process or core file.\n\
Packit Service 97d2fb
\n\
Packit Service 97d2fb
Program exits with return code 0 if all frames were shown without \
Packit Service 97d2fb
any errors.  If some frames were shown, but there were some non-fatal \
Packit Service 97d2fb
errors, possibly causing an incomplete backtrace, the program exits \
Packit Service 97d2fb
with return code 1.  If no frames could be shown, or a fatal error \
Packit Service 97d2fb
occured the program exits with return code 2.  If the program was \
Packit Service 97d2fb
invoked with bad or missing arguments it will exit with return code 64.")
Packit Service 97d2fb
    };
Packit Service 97d2fb
Packit Service 97d2fb
  argp_parse (&argp, argc, argv, 0, NULL, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  if (show_modules)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      printf ("PID %lld - %s module memory map\n", (long long) dwfl_pid (dwfl),
Packit Service 97d2fb
	      pid != 0 ? "process" : "core");
Packit Service 97d2fb
      if (dwfl_getmodules (dwfl, module_callback, NULL, 0) != 0)
Packit Service 97d2fb
	error (EXIT_BAD, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  struct frames frames;
Packit Service 97d2fb
  /* When maxframes is zero, then 2048 is just the initial allocation
Packit Service 97d2fb
     that will be increased using realloc in framecallback ().  */
Packit Service 97d2fb
  frames.allocated = maxframes == 0 ? 2048 : maxframes;
Packit Service 97d2fb
  frames.frames = 0;
Packit Service 97d2fb
  frames.frame = malloc (sizeof (struct frame) * frames.allocated);
Packit Service 97d2fb
  if (frames.frame == NULL)
Packit Service 97d2fb
    error (EXIT_BAD, errno, "malloc frames.frame");
Packit Service 97d2fb
Packit Service 97d2fb
  if (show_one_tid)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      int err = 0;
Packit Service 97d2fb
      switch (dwfl_getthread_frames (dwfl, pid, frame_callback, &frames))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	case DWARF_CB_OK:
Packit Service 97d2fb
	case DWARF_CB_ABORT:
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	case -1:
Packit Service 97d2fb
	  err = dwfl_errno ();
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	default:
Packit Service 97d2fb
	  abort ();
Packit Service 97d2fb
	}
Packit Service 97d2fb
      print_frames (&frames, pid, err, "dwfl_getthread_frames");
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      printf ("PID %lld - %s\n", (long long) dwfl_pid (dwfl),
Packit Service 97d2fb
	      pid != 0 ? "process" : "core");
Packit Service 97d2fb
      switch (dwfl_getthreads (dwfl, thread_callback, &frames))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	case DWARF_CB_OK:
Packit Service 97d2fb
	case DWARF_CB_ABORT:
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	case -1:
Packit Service 97d2fb
	  error (0, 0, "dwfl_getthreads: %s", dwfl_errmsg (-1));
Packit Service 97d2fb
	  break;
Packit Service 97d2fb
	default:
Packit Service 97d2fb
	  abort ();
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  free (frames.frame);
Packit Service 97d2fb
  dwfl_end (dwfl);
Packit Service 97d2fb
Packit Service 97d2fb
  if (core != NULL)
Packit Service 97d2fb
    elf_end (core);
Packit Service 97d2fb
Packit Service 97d2fb
  if (core_fd != -1)
Packit Service 97d2fb
    close (core_fd);
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
  if (! frames_shown)
Packit Service 97d2fb
    error (EXIT_BAD, 0, N_("Couldn't show any frames."));
Packit Service 97d2fb
Packit Service 97d2fb
  return error_message_count != 0 ? EXIT_ERROR : EXIT_OK;
Packit Service 97d2fb
}