xref: /third_party/elfutils/src/stack.c (revision da0c48c4)
1/* Unwinding of frames like gstack/pstack.
2   Copyright (C) 2013-2014 Red Hat, Inc.
3   This file is part of elfutils.
4
5   This file is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 3 of the License, or
8   (at your option) any later version.
9
10   elfutils is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18#include <config.h>
19#include <assert.h>
20#include <argp.h>
21#include <stdlib.h>
22#include <inttypes.h>
23#include <stdio.h>
24#include <stdio_ext.h>
25#include <string.h>
26#include <locale.h>
27#include <fcntl.h>
28#include ELFUTILS_HEADER(dwfl)
29
30#include <dwarf.h>
31#include <system.h>
32#include <printversion.h>
33
34/* Name and version of program.  */
35ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
36
37/* Bug report address.  */
38ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
39
40/* non-printable argp options.  */
41#define OPT_DEBUGINFO	0x100
42#define OPT_COREFILE	0x101
43
44static bool show_activation = false;
45static bool show_module = false;
46static bool show_build_id = false;
47static bool show_source = false;
48static bool show_one_tid = false;
49static bool show_quiet = false;
50static bool show_raw = false;
51static bool show_modules = false;
52static bool show_debugname = false;
53static bool show_inlines = false;
54
55static int maxframes = 256;
56
57struct frame
58{
59  Dwarf_Addr pc;
60  bool isactivation;
61};
62
63struct frames
64{
65  int frames;
66  int allocated;
67  struct frame *frame;
68};
69
70static Dwfl *dwfl = NULL;
71static pid_t pid = 0;
72static int core_fd = -1;
73static Elf *core = NULL;
74static const char *exec = NULL;
75static char *debuginfo_path = NULL;
76
77static const Dwfl_Callbacks proc_callbacks =
78  {
79    .find_elf = dwfl_linux_proc_find_elf,
80    .find_debuginfo = dwfl_standard_find_debuginfo,
81    .debuginfo_path = &debuginfo_path,
82  };
83
84static const Dwfl_Callbacks core_callbacks =
85  {
86    .find_elf = dwfl_build_id_find_elf,
87    .find_debuginfo = dwfl_standard_find_debuginfo,
88    .debuginfo_path = &debuginfo_path,
89  };
90
91#ifdef USE_DEMANGLE
92static size_t demangle_buffer_len = 0;
93static char *demangle_buffer = NULL;
94#endif
95
96/* Whether any frames have been shown at all.  Determines exit status.  */
97static bool frames_shown = false;
98
99/* Program exit codes. All frames shown without any errors is GOOD.
100   Some frames shown with some non-fatal errors is an ERROR.  A fatal
101   error or no frames shown at all is BAD.  A command line USAGE exit
102   is generated by argp_error.  */
103#define EXIT_OK     0
104#define EXIT_ERROR  1
105#define EXIT_BAD    2
106#define EXIT_USAGE 64
107
108static int
109get_addr_width (Dwfl_Module *mod)
110{
111  // Try to find the address wide if possible.
112  static int width = 0;
113  if (width == 0 && mod)
114    {
115      Dwarf_Addr bias;
116      Elf *elf = dwfl_module_getelf (mod, &bias);
117      if (elf)
118        {
119	  GElf_Ehdr ehdr_mem;
120	  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
121	  if (ehdr)
122	    width = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16;
123	}
124    }
125  if (width == 0)
126    width = 16;
127
128  return width;
129}
130
131static int
132module_callback (Dwfl_Module *mod, void **userdata __attribute__((unused)),
133		 const char *name, Dwarf_Addr start,
134		 void *arg __attribute__((unused)))
135{
136  /* Forces resolving of main elf and debug files. */
137  Dwarf_Addr bias;
138  Elf *elf = dwfl_module_getelf (mod, &bias);
139  Dwarf *dwarf = dwfl_module_getdwarf (mod, &bias);
140
141  Dwarf_Addr end;
142  const char *mainfile;
143  const char *debugfile;
144  const char *modname = dwfl_module_info (mod, NULL, NULL, &end, NULL,
145                                          NULL, &mainfile, &debugfile);
146  if (modname == NULL || strcmp (modname, name) != 0)
147    {
148      end = start + 1;
149      mainfile = NULL;
150      debugfile = NULL;
151    }
152
153  int width = get_addr_width (mod);
154  printf ("0x%0*" PRIx64 "-0x%0*" PRIx64 " %s\n",
155	  width, start, width, end, basename (name));
156
157  const unsigned char *id;
158  GElf_Addr id_vaddr;
159  int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
160  if (id_len > 0)
161    {
162      printf ("  [");
163      do
164	printf ("%02" PRIx8, *id++);
165      while (--id_len > 0);
166      printf ("]\n");
167    }
168
169  if (elf != NULL)
170    printf ("  %s\n", mainfile != NULL ? mainfile : "-");
171  if (dwarf != NULL)
172    printf ("  %s\n", debugfile != NULL ? debugfile : "-");
173
174  return DWARF_CB_OK;
175}
176
177static int
178frame_callback (Dwfl_Frame *state, void *arg)
179{
180  struct frames *frames = (struct frames *) arg;
181  int nr = frames->frames;
182  if (! dwfl_frame_pc (state, &frames->frame[nr].pc,
183		       &frames->frame[nr].isactivation))
184    return -1;
185
186  frames->frames++;
187  if (frames->frames == maxframes)
188    return DWARF_CB_ABORT;
189
190  if (frames->frames == frames->allocated)
191    {
192      frames->allocated *= 2;
193      frames->frame = realloc (frames->frame,
194			       sizeof (struct frame) * frames->allocated);
195      if (frames->frame == NULL)
196	error (EXIT_BAD, errno, "realloc frames.frame");
197    }
198
199  return DWARF_CB_OK;
200}
201
202static const char*
203die_name (Dwarf_Die *die)
204{
205  Dwarf_Attribute attr;
206  const char *name;
207  name = dwarf_formstring (dwarf_attr_integrate (die,
208						 DW_AT_MIPS_linkage_name,
209						 &attr)
210			   ?: dwarf_attr_integrate (die,
211						    DW_AT_linkage_name,
212						    &attr));
213  if (name == NULL)
214    name = dwarf_diename (die);
215
216  return name;
217}
218
219static void
220print_frame (int nr, Dwarf_Addr pc, bool isactivation,
221	     Dwarf_Addr pc_adjusted, Dwfl_Module *mod,
222	     const char *symname, Dwarf_Die *cudie,
223	     Dwarf_Die *die)
224{
225  int width = get_addr_width (mod);
226  printf ("#%-2u 0x%0*" PRIx64, nr, width, (uint64_t) pc);
227
228  if (show_activation)
229    printf ("%4s", ! isactivation ? "- 1" : "");
230
231  if (symname != NULL)
232    {
233#ifdef USE_DEMANGLE
234      // Require GNU v3 ABI by the "_Z" prefix.
235      if (! show_raw && symname[0] == '_' && symname[1] == 'Z')
236	{
237	  int status = -1;
238	  char *dsymname = __cxa_demangle (symname, demangle_buffer,
239					   &demangle_buffer_len, &status);
240	  if (status == 0)
241	    symname = demangle_buffer = dsymname;
242	}
243#endif
244      printf (" %s", symname);
245    }
246
247  const char* fname;
248  Dwarf_Addr start;
249  fname = dwfl_module_info(mod, NULL, &start,
250			   NULL, NULL, NULL, NULL, NULL);
251  if (show_module)
252    {
253      if (fname != NULL)
254	printf (" - %s", fname);
255    }
256
257  if (show_build_id)
258    {
259      const unsigned char *id;
260      GElf_Addr id_vaddr;
261      int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
262      if (id_len > 0)
263	{
264	  printf ("\n    [");
265	  do
266	    printf ("%02" PRIx8, *id++);
267	  while (--id_len > 0);
268	  printf ("]@0x%0" PRIx64 "+0x%" PRIx64,
269		  start, pc_adjusted - start);
270	}
271    }
272
273  if (show_source)
274    {
275      int line, col;
276      const char* sname;
277      line = col = -1;
278      sname = NULL;
279      if (die != NULL)
280	{
281	  Dwarf_Files *files;
282	  if (dwarf_getsrcfiles (cudie, &files, NULL) == 0)
283	    {
284	      Dwarf_Attribute attr;
285	      Dwarf_Word val;
286	      if (dwarf_formudata (dwarf_attr (die, DW_AT_call_file, &attr),
287				   &val) == 0)
288		{
289		  sname = dwarf_filesrc (files, val, NULL, NULL);
290		  if (dwarf_formudata (dwarf_attr (die, DW_AT_call_line,
291						   &attr), &val) == 0)
292		    {
293		      line = val;
294		      if (dwarf_formudata (dwarf_attr (die, DW_AT_call_column,
295						       &attr), &val) == 0)
296			col = val;
297		    }
298		}
299	    }
300	}
301      else
302	{
303	  Dwfl_Line *lineobj = dwfl_module_getsrc(mod, pc_adjusted);
304	  if (lineobj)
305	    sname = dwfl_lineinfo (lineobj, NULL, &line, &col, NULL, NULL);
306	}
307
308      if (sname != NULL)
309	{
310	  printf ("\n    %s", sname);
311	  if (line > 0)
312	    {
313	      printf (":%d", line);
314	      if (col > 0)
315		printf (":%d", col);
316	    }
317	}
318    }
319  printf ("\n");
320}
321
322static void
323print_inline_frames (int *nr, Dwarf_Addr pc, bool isactivation,
324		     Dwarf_Addr pc_adjusted, Dwfl_Module *mod,
325		     const char *symname, Dwarf_Die *cudie, Dwarf_Die *die)
326{
327  Dwarf_Die *scopes = NULL;
328  int nscopes = dwarf_getscopes_die (die, &scopes);
329  if (nscopes > 0)
330    {
331      /* scopes[0] == die, the lowest level, for which we already have
332	 the name.  This is the actual source location where it
333	 happened.  */
334      print_frame ((*nr)++, pc, isactivation, pc_adjusted, mod, symname,
335		   NULL, NULL);
336
337      /* last_scope is the source location where the next frame/function
338	 call was done. */
339      Dwarf_Die *last_scope = &scopes[0];
340      for (int i = 1; i < nscopes && (maxframes == 0 || *nr < maxframes); i++)
341	{
342	  Dwarf_Die *scope = &scopes[i];
343	  int tag = dwarf_tag (scope);
344	  if (tag != DW_TAG_inlined_subroutine
345	      && tag != DW_TAG_entry_point
346	      && tag != DW_TAG_subprogram)
347	    continue;
348
349	  symname = die_name (scope);
350	  print_frame ((*nr)++, pc, isactivation, pc_adjusted, mod, symname,
351		       cudie, last_scope);
352
353	  /* Found the "top-level" in which everything was inlined?  */
354	  if (tag == DW_TAG_subprogram)
355	    break;
356
357	  last_scope = scope;
358	}
359    }
360  free (scopes);
361}
362
363static void
364print_frames (struct frames *frames, pid_t tid, int dwflerr, const char *what)
365{
366  if (frames->frames > 0)
367    frames_shown = true;
368
369  printf ("TID %lld:\n", (long long) tid);
370  int frame_nr = 0;
371  for (int nr = 0; nr < frames->frames && (maxframes == 0
372					   || frame_nr < maxframes); nr++)
373    {
374      Dwarf_Addr pc = frames->frame[nr].pc;
375      bool isactivation = frames->frame[nr].isactivation;
376      Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
377
378      /* Get PC->SYMNAME.  */
379      Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
380      const char *symname = NULL;
381      Dwarf_Die die_mem;
382      Dwarf_Die *die = NULL;
383      Dwarf_Die *cudie = NULL;
384      if (mod && ! show_quiet)
385	{
386	  if (show_debugname)
387	    {
388	      Dwarf_Addr bias = 0;
389	      Dwarf_Die *scopes = NULL;
390	      cudie = dwfl_module_addrdie (mod, pc_adjusted, &bias);
391	      int nscopes = dwarf_getscopes (cudie, pc_adjusted - bias,
392					     &scopes);
393
394	      /* Find the first function-like DIE with a name in scope.  */
395	      for (int i = 0; symname == NULL && i < nscopes; i++)
396		{
397		  Dwarf_Die *scope = &scopes[i];
398		  int tag = dwarf_tag (scope);
399		  if (tag == DW_TAG_subprogram
400		      || tag == DW_TAG_inlined_subroutine
401		      || tag == DW_TAG_entry_point)
402		    symname = die_name (scope);
403
404		  if (symname != NULL)
405		    {
406		      die_mem = *scope;
407		      die = &die_mem;
408		    }
409		}
410	      free (scopes);
411	    }
412
413	  if (symname == NULL)
414	    symname = dwfl_module_addrname (mod, pc_adjusted);
415	}
416
417      if (show_inlines && die != NULL)
418	print_inline_frames (&frame_nr, pc, isactivation, pc_adjusted, mod,
419			     symname, cudie, die);
420      else
421	print_frame (frame_nr++, pc, isactivation, pc_adjusted, mod, symname,
422		     NULL, NULL);
423    }
424
425  if (frames->frames > 0 && frame_nr == maxframes)
426    error (0, 0, "tid %lld: shown max number of frames "
427	   "(%d, use -n 0 for unlimited)", (long long) tid, maxframes);
428  else if (dwflerr != 0)
429    {
430      if (frames->frames > 0)
431	{
432	  unsigned nr = frames->frames - 1;
433	  Dwarf_Addr pc = frames->frame[nr].pc;
434	  bool isactivation = frames->frame[nr].isactivation;
435	  Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
436	  Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
437	  const char *mainfile = NULL;
438	  const char *modname = dwfl_module_info (mod, NULL, NULL, NULL, NULL,
439						  NULL, &mainfile, NULL);
440	  if (modname == NULL || modname[0] == '\0')
441	    {
442	      if (mainfile != NULL)
443		modname = mainfile;
444	      else
445		modname = "<unknown>";
446	    }
447	  error (0, 0, "%s tid %lld at 0x%" PRIx64 " in %s: %s", what,
448		 (long long) tid, pc_adjusted, modname, dwfl_errmsg (dwflerr));
449	}
450      else
451	error (0, 0, "%s tid %lld: %s", what, (long long) tid,
452	       dwfl_errmsg (dwflerr));
453    }
454}
455
456static int
457thread_callback (Dwfl_Thread *thread, void *thread_arg)
458{
459  struct frames *frames = (struct frames *) thread_arg;
460  pid_t tid = dwfl_thread_tid (thread);
461  int err = 0;
462  frames->frames = 0;
463  switch (dwfl_thread_getframes (thread, frame_callback, thread_arg))
464    {
465    case DWARF_CB_OK:
466    case DWARF_CB_ABORT:
467      break;
468    case -1:
469      err = dwfl_errno ();
470      break;
471    default:
472      abort ();
473    }
474  print_frames (frames, tid, err, "dwfl_thread_getframes");
475  return DWARF_CB_OK;
476}
477
478static error_t
479parse_opt (int key, char *arg __attribute__ ((unused)),
480	   struct argp_state *state)
481{
482  switch (key)
483    {
484    case 'p':
485      pid = atoi (arg);
486      if (pid == 0)
487	argp_error (state, N_("-p PID should be a positive process id."));
488      break;
489
490    case OPT_COREFILE:
491      core_fd = open (arg, O_RDONLY);
492      if (core_fd < 0)
493	error (EXIT_BAD, errno, N_("Cannot open core file '%s'"), arg);
494      elf_version (EV_CURRENT);
495      core = elf_begin (core_fd, ELF_C_READ_MMAP, NULL);
496      if (core == NULL)
497	error (EXIT_BAD, 0, "core '%s' elf_begin: %s", arg, elf_errmsg(-1));
498      break;
499
500    case 'e':
501      exec = arg;
502      break;
503
504    case OPT_DEBUGINFO:
505      debuginfo_path = arg;
506      break;
507
508    case 'm':
509      show_module = true;
510      break;
511
512    case 's':
513      show_source = true;
514      break;
515
516    case 'a':
517      show_activation = true;
518      break;
519
520    case 'd':
521      show_debugname = true;
522      break;
523
524    case 'i':
525      show_inlines = show_debugname = true;
526      break;
527
528    case 'v':
529      show_activation = show_source = show_module = show_debugname = true;
530      show_inlines = true;
531      break;
532
533    case 'b':
534      show_build_id = true;
535      break;
536
537    case 'q':
538      show_quiet = true;
539      break;
540
541    case 'r':
542      show_raw = true;
543      break;
544
545    case '1':
546      show_one_tid = true;
547      break;
548
549    case 'n':
550      maxframes = atoi (arg);
551      if (maxframes < 0)
552	{
553	  argp_error (state, N_("-n MAXFRAMES should be 0 or higher."));
554	  return EINVAL;
555	}
556      break;
557
558    case 'l':
559      show_modules = true;
560      break;
561
562    case ARGP_KEY_END:
563      if (core == NULL && exec != NULL)
564	argp_error (state,
565		    N_("-e EXEC needs a core given by --core."));
566
567      if (pid == 0 && show_one_tid == true)
568	argp_error (state,
569		    N_("-1 needs a thread id given by -p."));
570
571      if ((pid == 0 && core == NULL) || (pid != 0 && core != NULL))
572	argp_error (state,
573		    N_("One of -p PID or --core COREFILE should be given."));
574
575      if (pid != 0)
576	{
577	  dwfl = dwfl_begin (&proc_callbacks);
578	  if (dwfl == NULL)
579	    error (EXIT_BAD, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
580
581	  int err = dwfl_linux_proc_report (dwfl, pid);
582	  if (err < 0)
583	    error (EXIT_BAD, 0, "dwfl_linux_proc_report pid %lld: %s",
584		   (long long) pid, dwfl_errmsg (-1));
585	  else if (err > 0)
586	    error (EXIT_BAD, err, "dwfl_linux_proc_report pid %lld",
587		   (long long) pid);
588	}
589
590      if (core != NULL)
591	{
592	  dwfl = dwfl_begin (&core_callbacks);
593	  if (dwfl == NULL)
594	    error (EXIT_BAD, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
595	  if (dwfl_core_file_report (dwfl, core, exec) < 0)
596	    error (EXIT_BAD, 0, "dwfl_core_file_report: %s", dwfl_errmsg (-1));
597	}
598
599      if (dwfl_report_end (dwfl, NULL, NULL) != 0)
600	error (EXIT_BAD, 0, "dwfl_report_end: %s", dwfl_errmsg (-1));
601
602      if (pid != 0)
603	{
604	  int err = dwfl_linux_proc_attach (dwfl, pid, false);
605	  if (err < 0)
606	    error (EXIT_BAD, 0, "dwfl_linux_proc_attach pid %lld: %s",
607		   (long long) pid, dwfl_errmsg (-1));
608	  else if (err > 0)
609	    error (EXIT_BAD, err, "dwfl_linux_proc_attach pid %lld",
610		   (long long) pid);
611	}
612
613      if (core != NULL)
614	{
615	  if (dwfl_core_file_attach (dwfl, core) < 0)
616	    error (EXIT_BAD, 0, "dwfl_core_file_attach: %s", dwfl_errmsg (-1));
617	}
618
619      /* Makes sure we are properly attached.  */
620      if (dwfl_pid (dwfl) < 0)
621	error (EXIT_BAD, 0, "dwfl_pid: %s\n", dwfl_errmsg (-1));
622      break;
623
624    default:
625      return ARGP_ERR_UNKNOWN;
626    }
627  return 0;
628}
629
630int
631main (int argc, char **argv)
632{
633  /* We use no threads here which can interfere with handling a stream.  */
634  __fsetlocking (stdin, FSETLOCKING_BYCALLER);
635  __fsetlocking (stdout, FSETLOCKING_BYCALLER);
636  __fsetlocking (stderr, FSETLOCKING_BYCALLER);
637
638  /* Set locale.  */
639  (void) setlocale (LC_ALL, "");
640
641  const struct argp_option options[] =
642    {
643      { NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
644      { "pid", 'p', "PID", 0,
645	N_("Show stack of process PID"), 0 },
646      { "core", OPT_COREFILE, "COREFILE", 0,
647	N_("Show stack found in COREFILE"), 0 },
648      {  "executable", 'e', "EXEC", 0, N_("(optional) EXECUTABLE that produced COREFILE"), 0 },
649      { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
650	N_("Search path for separate debuginfo files"), 0 },
651
652      { NULL, 0, NULL, 0, N_("Output selection options:"), 0 },
653      { "activation",  'a', NULL, 0,
654	N_("Additionally show frame activation"), 0 },
655      { "debugname",  'd', NULL, 0,
656	N_("Additionally try to lookup DWARF debuginfo name for frame address"),
657	0 },
658      { "inlines",  'i', NULL, 0,
659	N_("Additionally show inlined function frames using DWARF debuginfo if available (implies -d)"), 0 },
660      { "module",  'm', NULL, 0,
661	N_("Additionally show module file information"), 0 },
662      { "source",  's', NULL, 0,
663	N_("Additionally show source file information"), 0 },
664      { "verbose", 'v', NULL, 0,
665	N_("Show all additional information (activation, debugname, inlines, module and source)"), 0 },
666      { "quiet", 'q', NULL, 0,
667	N_("Do not resolve address to function symbol name"), 0 },
668      { "raw", 'r', NULL, 0,
669	N_("Show raw function symbol names, do not try to demangle names"), 0 },
670      { "build-id",  'b', NULL, 0,
671	N_("Show module build-id, load address and pc offset"), 0 },
672      { NULL, '1', NULL, 0,
673	N_("Show the backtrace of only one thread"), 0 },
674      { NULL, 'n', "MAXFRAMES", 0,
675	N_("Show at most MAXFRAMES per thread (default 256, use 0 for unlimited)"), 0 },
676      { "list-modules", 'l', NULL, 0,
677	N_("Show module memory map with build-id, elf and debug files detected"), 0 },
678      { NULL, 0, NULL, 0, NULL, 0 }
679    };
680
681  const struct argp argp =
682    {
683      .options = options,
684      .parser = parse_opt,
685      .doc = N_("Print a stack for each thread in a process or core file.\n\
686\n\
687Program exits with return code 0 if all frames were shown without \
688any errors.  If some frames were shown, but there were some non-fatal \
689errors, possibly causing an incomplete backtrace, the program exits \
690with return code 1.  If no frames could be shown, or a fatal error \
691occurred the program exits with return code 2.  If the program was \
692invoked with bad or missing arguments it will exit with return code 64.")
693    };
694
695  argp_parse (&argp, argc, argv, 0, NULL, NULL);
696
697  if (show_modules)
698    {
699      printf ("PID %lld - %s module memory map\n", (long long) dwfl_pid (dwfl),
700	      pid != 0 ? "process" : "core");
701      if (dwfl_getmodules (dwfl, module_callback, NULL, 0) != 0)
702	error (EXIT_BAD, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
703    }
704
705  struct frames frames;
706  /* When maxframes is zero, then 2048 is just the initial allocation
707     that will be increased using realloc in framecallback ().  */
708  frames.allocated = maxframes == 0 ? 2048 : maxframes;
709  frames.frames = 0;
710  frames.frame = malloc (sizeof (struct frame) * frames.allocated);
711  if (frames.frame == NULL)
712    error (EXIT_BAD, errno, "malloc frames.frame");
713
714  if (show_one_tid)
715    {
716      int err = 0;
717      switch (dwfl_getthread_frames (dwfl, pid, frame_callback, &frames))
718	{
719	case DWARF_CB_OK:
720	case DWARF_CB_ABORT:
721	  break;
722	case -1:
723	  err = dwfl_errno ();
724	  break;
725	default:
726	  abort ();
727	}
728      print_frames (&frames, pid, err, "dwfl_getthread_frames");
729    }
730  else
731    {
732      printf ("PID %lld - %s\n", (long long) dwfl_pid (dwfl),
733	      pid != 0 ? "process" : "core");
734      switch (dwfl_getthreads (dwfl, thread_callback, &frames))
735	{
736	case DWARF_CB_OK:
737	case DWARF_CB_ABORT:
738	  break;
739	case -1:
740	  error (0, 0, "dwfl_getthreads: %s", dwfl_errmsg (-1));
741	  break;
742	default:
743	  abort ();
744	}
745    }
746  free (frames.frame);
747  dwfl_end (dwfl);
748
749  if (core != NULL)
750    elf_end (core);
751
752  if (core_fd != -1)
753    close (core_fd);
754
755#ifdef USE_DEMANGLE
756  free (demangle_buffer);
757#endif
758
759  if (! frames_shown)
760    error (EXIT_BAD, 0, N_("Couldn't show any frames."));
761
762  return error_message_count != 0 ? EXIT_ERROR : EXIT_OK;
763}
764