103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* Unwinding of frames like gstack/pstack.
203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   Copyright (C) 2013-2014 Red Hat, Inc.
303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is part of elfutils.
403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   This file is free software; you can redistribute it and/or modify
603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   it under the terms of the GNU General Public License as published by
703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   the Free Software Foundation; either version 3 of the License, or
803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   (at your option) any later version.
903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   elfutils is distributed in the hope that it will be useful, but
1103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   WITHOUT ANY WARRANTY; without even the implied warranty of
1203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   GNU General Public License for more details.
1403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   You should have received a copy of the GNU General Public License
1603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
1803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <config.h>
1903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <assert.h>
2003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <argp.h>
2103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <error.h>
2203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <stdlib.h>
2303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <inttypes.h>
2403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <stdio.h>
2503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <stdio_ext.h>
2603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <string.h>
2703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <locale.h>
2803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <fcntl.h>
2903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include ELFUTILS_HEADER(dwfl)
3003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
3103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <dwarf.h>
3203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#include <system.h>
3303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
3403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* Name and version of program.  */
3503333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic void print_version (FILE *stream, struct argp_state *state);
3603333823c75a1c1887e923828113a1b0fd12020cElliott HughesARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
3703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
3803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* Bug report address.  */
3903333823c75a1c1887e923828113a1b0fd12020cElliott HughesARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
4003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
4103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* non-printable argp options.  */
4203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define OPT_DEBUGINFO	0x100
4303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define OPT_COREFILE	0x101
4403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
4503333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic bool show_activation = false;
4603333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic bool show_module = false;
4703333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic bool show_build_id = false;
4803333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic bool show_source = false;
4903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic bool show_one_tid = false;
5003333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic bool show_quiet = false;
5103333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic bool show_raw = false;
5203333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic bool show_modules = false;
5303333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic bool show_debugname = false;
5403333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic bool show_inlines = false;
5503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
5603333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int maxframes = 256;
5703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
5803333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstruct frame
5903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
6003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwarf_Addr pc;
6103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  bool isactivation;
6203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes};
6303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
6403333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstruct frames
6503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
6603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int frames;
6703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int allocated;
6803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  struct frame *frame;
6903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes};
7003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
7103333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic Dwfl *dwfl = NULL;
7203333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic pid_t pid = 0;
7303333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int core_fd = -1;
7403333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic Elf *core = NULL;
7503333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic const char *exec = NULL;
7603333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic char *debuginfo_path = NULL;
7703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
7803333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic const Dwfl_Callbacks proc_callbacks =
7903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  {
8003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    .find_elf = dwfl_linux_proc_find_elf,
8103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    .find_debuginfo = dwfl_standard_find_debuginfo,
8203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    .debuginfo_path = &debuginfo_path,
8303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  };
8403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
8503333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic const Dwfl_Callbacks core_callbacks =
8603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  {
8703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    .find_elf = dwfl_build_id_find_elf,
8803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    .find_debuginfo = dwfl_standard_find_debuginfo,
8903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    .debuginfo_path = &debuginfo_path,
9003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  };
9103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
9203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#ifdef USE_DEMANGLE
9303333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic size_t demangle_buffer_len = 0;
9403333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic char *demangle_buffer = NULL;
9503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#endif
9603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
9703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* Whether any frames have been shown at all.  Determines exit status.  */
9803333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic bool frames_shown = false;
9903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
10003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes/* Program exit codes. All frames shown without any errors is GOOD.
10103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   Some frames shown with some non-fatal errors is an ERROR.  A fatal
10203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   error or no frames shown at all is BAD.  A command line USAGE exit
10303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes   is generated by argp_error.  */
10403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define EXIT_OK     0
10503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define EXIT_ERROR  1
10603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define EXIT_BAD    2
10703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#define EXIT_USAGE 64
10803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
10903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
11003333823c75a1c1887e923828113a1b0fd12020cElliott Hughesget_addr_width (Dwfl_Module *mod)
11103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
11203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  // Try to find the address wide if possible.
11303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  static int width = 0;
11403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (width == 0 && mod)
11503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
11603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Addr bias;
11703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Elf *elf = dwfl_module_getelf (mod, &bias);
11803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (elf)
11903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes        {
12003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  GElf_Ehdr ehdr_mem;
12103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
12203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (ehdr)
12303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    width = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16;
12403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
12503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
12603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (width == 0)
12703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    width = 16;
12803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
12903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return width;
13003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
13103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
13203333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
13303333823c75a1c1887e923828113a1b0fd12020cElliott Hughesmodule_callback (Dwfl_Module *mod, void **userdata __attribute__((unused)),
13403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		 const char *name, Dwarf_Addr start,
13503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		 void *arg __attribute__((unused)))
13603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
13703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* Forces resolving of main elf and debug files. */
13803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwarf_Addr bias;
13903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Elf *elf = dwfl_module_getelf (mod, &bias);
14003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwarf *dwarf = dwfl_module_getdwarf (mod, &bias);
14103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
14203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwarf_Addr end;
14303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  const char *mainfile;
14403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  const char *debugfile;
14503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  const char *modname = dwfl_module_info (mod, NULL, NULL, &end, NULL,
14603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes                                          NULL, &mainfile, &debugfile);
14703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  assert (strcmp (modname, name) == 0);
14803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
14903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int width = get_addr_width (mod);
15003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  printf ("0x%0*" PRIx64 "-0x%0*" PRIx64 " %s\n",
15103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  width, start, width, end, basename (name));
15203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
15303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  const unsigned char *id;
15403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  GElf_Addr id_vaddr;
15503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
15603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (id_len > 0)
15703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
15803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      printf ("  [");
15903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      do
16003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	printf ("%02" PRIx8, *id++);
16103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      while (--id_len > 0);
16203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      printf ("]\n");
16303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
16403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
16503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (elf != NULL)
16603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    printf ("  %s\n", mainfile != NULL ? mainfile : "-");
16703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (dwarf != NULL)
16803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    printf ("  %s\n", debugfile != NULL ? debugfile : "-");
16903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
17003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return DWARF_CB_OK;
17103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
17203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
17303333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
17403333823c75a1c1887e923828113a1b0fd12020cElliott Hughesframe_callback (Dwfl_Frame *state, void *arg)
17503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
17603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  struct frames *frames = (struct frames *) arg;
17703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int nr = frames->frames;
17803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (! dwfl_frame_pc (state, &frames->frame[nr].pc,
17903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		       &frames->frame[nr].isactivation))
18003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    return -1;
18103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
18203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  frames->frames++;
18303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (frames->frames == maxframes)
18403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    return DWARF_CB_ABORT;
18503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
18603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (frames->frames == frames->allocated)
18703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
18803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      frames->allocated *= 2;
18903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      frames->frame = realloc (frames->frame,
19003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			       sizeof (struct frame) * frames->allocated);
19103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (frames->frame == NULL)
19203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	error (EXIT_BAD, errno, "realloc frames.frame");
19303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
19403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
19503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return DWARF_CB_OK;
19603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
19703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
19803333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic const char*
19903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesdie_name (Dwarf_Die *die)
20003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
20103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwarf_Attribute attr;
20203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  const char *name;
20303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  name = dwarf_formstring (dwarf_attr_integrate (die,
20403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						 DW_AT_MIPS_linkage_name,
20503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						 &attr)
20603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			   ?: dwarf_attr_integrate (die,
20703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						    DW_AT_linkage_name,
20803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						    &attr));
20903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (name == NULL)
21003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    name = dwarf_diename (die);
21103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
21203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return name;
21303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
21403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
21503333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic void
21603333823c75a1c1887e923828113a1b0fd12020cElliott Hughesprint_frame (int nr, Dwarf_Addr pc, bool isactivation,
21703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	     Dwarf_Addr pc_adjusted, Dwfl_Module *mod,
21803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	     const char *symname, Dwarf_Die *cudie,
21903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	     Dwarf_Die *die)
22003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
22103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int width = get_addr_width (mod);
22203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  printf ("#%-2u 0x%0*" PRIx64, nr, width, (uint64_t) pc);
22303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
22403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (show_activation)
22503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    printf ("%4s", ! isactivation ? "- 1" : "");
22603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
22703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (symname != NULL)
22803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
22903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#ifdef USE_DEMANGLE
23003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      // Require GNU v3 ABI by the "_Z" prefix.
23103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (! show_raw && symname[0] == '_' && symname[1] == 'Z')
23203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
23303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  int status = -1;
23403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  char *dsymname = __cxa_demangle (symname, demangle_buffer,
23503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes					   &demangle_buffer_len, &status);
23603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (status == 0)
23703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    symname = demangle_buffer = dsymname;
23803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
23903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#endif
24003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      printf (" %s", symname);
24103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
24203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
24303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  const char* fname;
24403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwarf_Addr start;
24503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  fname = dwfl_module_info(mod, NULL, &start,
24603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			   NULL, NULL, NULL, NULL, NULL);
24703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (show_module)
24803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
24903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (fname != NULL)
25003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	printf (" - %s", fname);
25103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
25203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
25303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (show_build_id)
25403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
25503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      const unsigned char *id;
25603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      GElf_Addr id_vaddr;
25703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
25803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (id_len > 0)
25903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
26003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  printf ("\n    [");
26103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  do
26203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    printf ("%02" PRIx8, *id++);
26303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  while (--id_len > 0);
26403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  printf ("]@0x%0" PRIx64 "+0x%" PRIx64,
26503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  start, pc_adjusted - start);
26603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
26703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
26803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
26903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (show_source)
27003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
27103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      int line, col;
27203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      const char* sname;
27303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      line = col = -1;
27403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      sname = NULL;
27503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (die != NULL)
27603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
27703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  Dwarf_Files *files;
27803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (dwarf_getsrcfiles (cudie, &files, NULL) == 0)
27903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
28003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      Dwarf_Attribute attr;
28103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      Dwarf_Word val;
28203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (dwarf_formudata (dwarf_attr (die, DW_AT_call_file, &attr),
28303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes				   &val) == 0)
28403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		{
28503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  sname = dwarf_filesrc (files, val, NULL, NULL);
28603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  if (dwarf_formudata (dwarf_attr (die, DW_AT_call_line,
28703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						   &attr), &val) == 0)
28803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    {
28903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      line = val;
29003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      if (dwarf_formudata (dwarf_attr (die, DW_AT_call_column,
29103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						       &attr), &val) == 0)
29203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			col = val;
29303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    }
29403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		}
29503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
29603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
29703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      else
29803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
29903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  Dwfl_Line *lineobj = dwfl_module_getsrc(mod, pc_adjusted);
30003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (lineobj)
30103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    sname = dwfl_lineinfo (lineobj, NULL, &line, &col, NULL, NULL);
30203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
30303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
30403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (sname != NULL)
30503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
30603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  printf ("\n    %s", sname);
30703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (line > 0)
30803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
30903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      printf (":%d", line);
31003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (col > 0)
31103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		printf (":%d", col);
31203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
31303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
31403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
31503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  printf ("\n");
31603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
31703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
31803333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic void
31903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesprint_inline_frames (int *nr, Dwarf_Addr pc, bool isactivation,
32003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		     Dwarf_Addr pc_adjusted, Dwfl_Module *mod,
32103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		     const char *symname, Dwarf_Die *cudie, Dwarf_Die *die)
32203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
32303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  Dwarf_Die *scopes = NULL;
32403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int nscopes = dwarf_getscopes_die (die, &scopes);
32503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (nscopes > 0)
32603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
32703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* scopes[0] == die, the lowest level, for which we already have
32803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	 the name.  This is the actual source location where it
32903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	 happened.  */
33003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      print_frame ((*nr)++, pc, isactivation, pc_adjusted, mod, symname,
33103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		   NULL, NULL);
33203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
33303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* last_scope is the source location where the next frame/function
33403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	 call was done. */
33503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Die *last_scope = &scopes[0];
33603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      for (int i = 1; i < nscopes && (maxframes == 0 || *nr < maxframes); i++)
33703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
33803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  Dwarf_Die *scope = &scopes[i];
33903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  int tag = dwarf_tag (scope);
34003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (tag != DW_TAG_inlined_subroutine
34103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      && tag != DW_TAG_entry_point
34203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      && tag != DW_TAG_subprogram)
34303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    continue;
34403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
34503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  symname = die_name (scope);
34603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  print_frame ((*nr)++, pc, isactivation, pc_adjusted, mod, symname,
34703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		       cudie, last_scope);
34803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
34903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  /* Found the "top-level" in which everything was inlined?  */
35003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (tag == DW_TAG_subprogram)
35103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    break;
35203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
35303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  last_scope = scope;
35403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
35503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
35603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  free (scopes);
35703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
35803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
35903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic void
36003333823c75a1c1887e923828113a1b0fd12020cElliott Hughesprint_frames (struct frames *frames, pid_t tid, int dwflerr, const char *what)
36103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
36203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (frames->frames > 0)
36303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    frames_shown = true;
36403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
36503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  printf ("TID %d:\n", tid);
36603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int frame_nr = 0;
36703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  for (int nr = 0; nr < frames->frames && (maxframes == 0
36803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes					   || frame_nr < maxframes); nr++)
36903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
37003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Addr pc = frames->frame[nr].pc;
37103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      bool isactivation = frames->frame[nr].isactivation;
37203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
37303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
37403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* Get PC->SYMNAME.  */
37503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
37603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      const char *symname = NULL;
37703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Die die_mem;
37803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Die *die = NULL;
37903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      Dwarf_Die *cudie = NULL;
38003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (mod && ! show_quiet)
38103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
38203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (show_debugname)
38303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
38403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      Dwarf_Addr bias = 0;
38503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      Dwarf_Die *scopes = NULL;
38603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      cudie = dwfl_module_addrdie (mod, pc_adjusted, &bias);
38703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      int nscopes = dwarf_getscopes (cudie, pc_adjusted - bias,
38803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes					     &scopes);
38903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
39003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      /* Find the first function-like DIE with a name in scope.  */
39103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      for (int i = 0; symname == NULL && i < nscopes; i++)
39203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		{
39303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  Dwarf_Die *scope = &scopes[i];
39403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  int tag = dwarf_tag (scope);
39503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  if (tag == DW_TAG_subprogram
39603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      || tag == DW_TAG_inlined_subroutine
39703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      || tag == DW_TAG_entry_point)
39803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    symname = die_name (scope);
39903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
40003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		  if (symname != NULL)
40103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    {
40203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      die_mem = *scope;
40303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		      die = &die_mem;
40403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    }
40503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		}
40603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      free (scopes);
40703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
40803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
40903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (symname == NULL)
41003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    symname = dwfl_module_addrname (mod, pc_adjusted);
41103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
41203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
41303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (show_inlines && die != NULL)
41403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	print_inline_frames (&frame_nr, pc, isactivation, pc_adjusted, mod,
41503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes			     symname, cudie, die);
41603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      else
41703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	print_frame (frame_nr++, pc, isactivation, pc_adjusted, mod, symname,
41803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		     NULL, NULL);
41903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
42003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
42103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (frames->frames > 0 && frame_nr == maxframes)
42203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    error (0, 0, "tid %d: shown max number of frames "
42303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	   "(%d, use -n 0 for unlimited)", tid, maxframes);
42403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  else if (dwflerr != 0)
42503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
42603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (frames->frames > 0)
42703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
42803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  unsigned nr = frames->frames - 1;
42903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  Dwarf_Addr pc = frames->frame[nr].pc;
43003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  bool isactivation = frames->frame[nr].isactivation;
43103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
43203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
43303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  const char *mainfile = NULL;
43403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  const char *modname = dwfl_module_info (mod, NULL, NULL, NULL, NULL,
43503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes						  NULL, &mainfile, NULL);
43603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (modname == NULL || modname[0] == '\0')
43703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    {
43803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      if (mainfile != NULL)
43903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		modname = mainfile;
44003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      else
44103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		modname = "<unknown>";
44203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    }
44303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  error (0, 0, "%s tid %d at 0x%" PRIx64 " in %s: %s", what, tid,
44403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		 pc_adjusted, modname, dwfl_errmsg (dwflerr));
44503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
44603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      else
44703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	error (0, 0, "%s tid %d: %s", what, tid, dwfl_errmsg (dwflerr));
44803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
44903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
45003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
45103333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic int
45203333823c75a1c1887e923828113a1b0fd12020cElliott Hughesthread_callback (Dwfl_Thread *thread, void *thread_arg)
45303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
45403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  struct frames *frames = (struct frames *) thread_arg;
45503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  pid_t tid = dwfl_thread_tid (thread);
45603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  int err = 0;
45703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  frames->frames = 0;
45803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  switch (dwfl_thread_getframes (thread, frame_callback, thread_arg))
45903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
46003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DWARF_CB_OK:
46103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case DWARF_CB_ABORT:
46203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
46303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case -1:
46403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      err = dwfl_errno ();
46503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
46603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    default:
46703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      abort ();
46803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
46903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  print_frames (frames, tid, err, "dwfl_thread_getframes");
47003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return DWARF_CB_OK;
47103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
47203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
47303333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic void
47403333823c75a1c1887e923828113a1b0fd12020cElliott Hughesprint_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
47503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
47603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  fprintf (stream, "stack (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
47703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
47803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
47903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesstatic error_t
48003333823c75a1c1887e923828113a1b0fd12020cElliott Hughesparse_opt (int key, char *arg __attribute__ ((unused)),
48103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	   struct argp_state *state)
48203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
48303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  switch (key)
48403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
48503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 'p':
48603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      pid = atoi (arg);
48703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (pid == 0)
48803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	argp_error (state, N_("-p PID should be a positive process id."));
48903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
49003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
49103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case OPT_COREFILE:
49203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      core_fd = open (arg, O_RDONLY);
49303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (core_fd < 0)
49403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	error (EXIT_BAD, errno, N_("Cannot open core file '%s'"), arg);
49503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      elf_version (EV_CURRENT);
49603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      core = elf_begin (core_fd, ELF_C_READ_MMAP, NULL);
49703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (core == NULL)
49803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	error (EXIT_BAD, 0, "core '%s' elf_begin: %s", arg, elf_errmsg(-1));
49903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
50003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
50103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 'e':
50203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      exec = arg;
50303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
50403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
50503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case OPT_DEBUGINFO:
50603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      debuginfo_path = arg;
50703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
50803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
50903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 'm':
51003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      show_module = true;
51103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
51203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
51303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 's':
51403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      show_source = true;
51503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
51603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
51703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 'a':
51803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      show_activation = true;
51903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
52003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
52103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 'd':
52203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      show_debugname = true;
52303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
52403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
52503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 'i':
52603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      show_inlines = show_debugname = true;
52703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
52803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
52903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 'v':
53003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      show_activation = show_source = show_module = show_debugname = true;
53103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      show_inlines = true;
53203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
53303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
53403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 'b':
53503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      show_build_id = true;
53603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
53703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
53803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 'q':
53903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      show_quiet = true;
54003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
54103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
54203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 'r':
54303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      show_raw = true;
54403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
54503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
54603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case '1':
54703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      show_one_tid = true;
54803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
54903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
55003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 'n':
55103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      maxframes = atoi (arg);
55203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (maxframes < 0)
55303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
55403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  argp_error (state, N_("-n MAXFRAMES should be 0 or higher."));
55503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  return EINVAL;
55603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
55703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
55803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
55903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case 'l':
56003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      show_modules = true;
56103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
56203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
56303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    case ARGP_KEY_END:
56403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (core == NULL && exec != NULL)
56503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	argp_error (state,
56603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    N_("-e EXEC needs a core given by --core."));
56703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
56803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (pid == 0 && show_one_tid == true)
56903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	argp_error (state,
57003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    N_("-1 needs a thread id given by -p."));
57103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
57203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if ((pid == 0 && core == NULL) || (pid != 0 && core != NULL))
57303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	argp_error (state,
57403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		    N_("One of -p PID or --core COREFILE should be given."));
57503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
57603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (pid != 0)
57703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
57803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  dwfl = dwfl_begin (&proc_callbacks);
57903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (dwfl == NULL)
58003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    error (EXIT_BAD, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
58103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
58203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  int err = dwfl_linux_proc_report (dwfl, pid);
58303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (err < 0)
58403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    error (EXIT_BAD, 0, "dwfl_linux_proc_report pid %d: %s", pid,
58503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		   dwfl_errmsg (-1));
58603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  else if (err > 0)
58703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    error (EXIT_BAD, err, "dwfl_linux_proc_report pid %d", pid);
58803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
58903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
59003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (core != NULL)
59103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
59203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  dwfl = dwfl_begin (&core_callbacks);
59303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (dwfl == NULL)
59403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    error (EXIT_BAD, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
59503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (dwfl_core_file_report (dwfl, core, exec) < 0)
59603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    error (EXIT_BAD, 0, "dwfl_core_file_report: %s", dwfl_errmsg (-1));
59703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
59803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
59903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (dwfl_report_end (dwfl, NULL, NULL) != 0)
60003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	error (EXIT_BAD, 0, "dwfl_report_end: %s", dwfl_errmsg (-1));
60103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
60203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (pid != 0)
60303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
60403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  int err = dwfl_linux_proc_attach (dwfl, pid, false);
60503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (err < 0)
60603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    error (EXIT_BAD, 0, "dwfl_linux_proc_attach pid %d: %s", pid,
60703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes		   dwfl_errmsg (-1));
60803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  else if (err > 0)
60903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    error (EXIT_BAD, err, "dwfl_linux_proc_attach pid %d", pid);
61003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
61103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
61203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (core != NULL)
61303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
61403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  if (dwfl_core_file_attach (dwfl, core) < 0)
61503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	    error (EXIT_BAD, 0, "dwfl_core_file_report: %s", dwfl_errmsg (-1));
61603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
61703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
61803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      /* Makes sure we are properly attached.  */
61903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (dwfl_pid (dwfl) < 0)
62003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	error (EXIT_BAD, 0, "dwfl_pid: %s\n", dwfl_errmsg (-1));
62103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      break;
62203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
62303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    default:
62403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      return ARGP_ERR_UNKNOWN;
62503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
62603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return 0;
62703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
62803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
62903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesint
63003333823c75a1c1887e923828113a1b0fd12020cElliott Hughesmain (int argc, char **argv)
63103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes{
63203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* We use no threads here which can interfere with handling a stream.  */
63303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  __fsetlocking (stdin, FSETLOCKING_BYCALLER);
63403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  __fsetlocking (stdout, FSETLOCKING_BYCALLER);
63503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  __fsetlocking (stderr, FSETLOCKING_BYCALLER);
63603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
63703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* Set locale.  */
63803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  (void) setlocale (LC_ALL, "");
63903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
64003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  const struct argp_option options[] =
64103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
64203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
64303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { "pid", 'p', "PID", 0,
64403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Show stack of process PID"), 0 },
64503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { "core", OPT_COREFILE, "COREFILE", 0,
64603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Show stack found in COREFILE"), 0 },
64703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      {  "executable", 'e', "EXEC", 0, N_("(optional) EXECUTABLE that produced COREFILE"), 0 },
64803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
64903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Search path for separate debuginfo files"), 0 },
65003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
65103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { NULL, 0, NULL, 0, N_("Output selection options:"), 0 },
65203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { "activation",  'a', NULL, 0,
65303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Additionally show frame activation"), 0 },
65403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { "debugname",  'd', NULL, 0,
65503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Additionally try to lookup DWARF debuginfo name for frame address"),
65603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	0 },
65703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { "inlines",  'i', NULL, 0,
65803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Additionally show inlined function frames using DWARF debuginfo if available (implies -d)"), 0 },
65903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { "module",  'm', NULL, 0,
66003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Additionally show module file information"), 0 },
66103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { "source",  's', NULL, 0,
66203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Additionally show source file information"), 0 },
66303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { "verbose", 'v', NULL, 0,
66403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Show all additional information (activation, debugname, inlines, module and source)"), 0 },
66503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { "quiet", 'q', NULL, 0,
66603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Do not resolve address to function symbol name"), 0 },
66703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { "raw", 'r', NULL, 0,
66803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Show raw function symbol names, do not try to demangle names"), 0 },
66903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { "build-id",  'b', NULL, 0,
67003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Show module build-id, load address and pc offset"), 0 },
67103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { NULL, '1', NULL, 0,
67203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Show the backtrace of only one thread"), 0 },
67303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { NULL, 'n', "MAXFRAMES", 0,
67403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Show at most MAXFRAMES per thread (default 256, use 0 for unlimited)"), 0 },
67503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { "list-modules", 'l', NULL, 0,
67603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	N_("Show module memory map with build-id, elf and debug files detected"), 0 },
67703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      { NULL, 0, NULL, 0, NULL, 0 }
67803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    };
67903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
68003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  const struct argp argp =
68103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
68203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      .options = options,
68303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      .parser = parse_opt,
68403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      .doc = N_("Print a stack for each thread in a process or core file.\v\
68503333823c75a1c1887e923828113a1b0fd12020cElliott HughesProgram exits with return code 0 if all frames were shown without \
68603333823c75a1c1887e923828113a1b0fd12020cElliott Hughesany errors.  If some frames were shown, but there were some non-fatal \
68703333823c75a1c1887e923828113a1b0fd12020cElliott Hugheserrors, possibly causing an incomplete backtrace, the program exits \
68803333823c75a1c1887e923828113a1b0fd12020cElliott Hugheswith return code 1.  If no frames could be shown, or a fatal error \
68903333823c75a1c1887e923828113a1b0fd12020cElliott Hughesoccured the program exits with return code 2.  If the program was \
69003333823c75a1c1887e923828113a1b0fd12020cElliott Hughesinvoked with bad or missing arguments it will exit with return code 64.")
69103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    };
69203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
69303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  argp_parse (&argp, argc, argv, 0, NULL, NULL);
69403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
69503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (show_modules)
69603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
69703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      printf ("PID %d - %s module memory map\n", dwfl_pid (dwfl),
69803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	      pid != 0 ? "process" : "core");
69903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      if (dwfl_getmodules (dwfl, module_callback, NULL, 0) != 0)
70003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	error (EXIT_BAD, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
70103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
70203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
70303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  struct frames frames;
70403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  /* When maxframes is zero, then 2048 is just the initial allocation
70503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes     that will be increased using realloc in framecallback ().  */
70603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  frames.allocated = maxframes == 0 ? 2048 : maxframes;
70703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  frames.frames = 0;
70803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  frames.frame = malloc (sizeof (struct frame) * frames.allocated);
70903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (frames.frame == NULL)
71003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    error (EXIT_BAD, errno, "malloc frames.frame");
71103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
71203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (show_one_tid)
71303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
71403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      int err = 0;
71503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      switch (dwfl_getthread_frames (dwfl, pid, frame_callback, &frames))
71603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
71703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	case DWARF_CB_OK:
71803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	case DWARF_CB_ABORT:
71903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  break;
72003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	case -1:
72103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  err = dwfl_errno ();
72203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  break;
72303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	default:
72403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  abort ();
72503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
72603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      print_frames (&frames, pid, err, "dwfl_getthread_frames");
72703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
72803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  else
72903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    {
73003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      printf ("PID %d - %s\n", dwfl_pid (dwfl), pid != 0 ? "process" : "core");
73103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes      switch (dwfl_getthreads (dwfl, thread_callback, &frames))
73203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	{
73303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	case DWARF_CB_OK:
73403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	case DWARF_CB_ABORT:
73503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  break;
73603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	case -1:
73703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  error (0, 0, "dwfl_getthreads: %s", dwfl_errmsg (-1));
73803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  break;
73903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	default:
74003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	  abort ();
74103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes	}
74203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    }
74303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  free (frames.frame);
74403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  dwfl_end (dwfl);
74503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
74603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (core != NULL)
74703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    elf_end (core);
74803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
74903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (core_fd != -1)
75003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    close (core_fd);
75103333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
75203333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#ifdef USE_DEMANGLE
75303333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  free (demangle_buffer);
75403333823c75a1c1887e923828113a1b0fd12020cElliott Hughes#endif
75503333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
75603333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  if (! frames_shown)
75703333823c75a1c1887e923828113a1b0fd12020cElliott Hughes    error (EXIT_BAD, 0, N_("Couldn't show any frames."));
75803333823c75a1c1887e923828113a1b0fd12020cElliott Hughes
75903333823c75a1c1887e923828113a1b0fd12020cElliott Hughes  return error_message_count != 0 ? EXIT_ERROR : EXIT_OK;
76003333823c75a1c1887e923828113a1b0fd12020cElliott Hughes}
761