Blame src/stack.c

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