• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.  */
35 ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
36 
37 /* Bug report address.  */
38 ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
39 
40 /* non-printable argp options.  */
41 #define OPT_DEBUGINFO	0x100
42 #define OPT_COREFILE	0x101
43 
44 static bool show_activation = false;
45 static bool show_module = false;
46 static bool show_build_id = false;
47 static bool show_source = false;
48 static bool show_one_tid = false;
49 static bool show_quiet = false;
50 static bool show_raw = false;
51 static bool show_modules = false;
52 static bool show_debugname = false;
53 static bool show_inlines = false;
54 
55 static int maxframes = 256;
56 
57 struct frame
58 {
59   Dwarf_Addr pc;
60   bool isactivation;
61 };
62 
63 struct frames
64 {
65   int frames;
66   int allocated;
67   struct frame *frame;
68 };
69 
70 static Dwfl *dwfl = NULL;
71 static pid_t pid = 0;
72 static int core_fd = -1;
73 static Elf *core = NULL;
74 static const char *exec = NULL;
75 static char *debuginfo_path = NULL;
76 
77 static 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 
84 static 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
92 static size_t demangle_buffer_len = 0;
93 static char *demangle_buffer = NULL;
94 #endif
95 
96 /* Whether any frames have been shown at all.  Determines exit status.  */
97 static 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 
108 static int
get_addr_width(Dwfl_Module * mod)109 get_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 
131 static int
module_callback(Dwfl_Module * mod,void ** userdata,const char * name,Dwarf_Addr start,void * arg)132 module_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 
177 static int
frame_callback(Dwfl_Frame * state,void * arg)178 frame_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 
202 static const char*
die_name(Dwarf_Die * die)203 die_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 
219 static void
print_frame(int nr,Dwarf_Addr pc,bool isactivation,Dwarf_Addr pc_adjusted,Dwfl_Module * mod,const char * symname,Dwarf_Die * cudie,Dwarf_Die * die)220 print_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 
322 static void
print_inline_frames(int * nr,Dwarf_Addr pc,bool isactivation,Dwarf_Addr pc_adjusted,Dwfl_Module * mod,const char * symname,Dwarf_Die * cudie,Dwarf_Die * die)323 print_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 
363 static void
print_frames(struct frames * frames,pid_t tid,int dwflerr,const char * what)364 print_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 
456 static int
thread_callback(Dwfl_Thread * thread,void * thread_arg)457 thread_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 
478 static error_t
parse_opt(int key,char * arg,struct argp_state * state)479 parse_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 
630 int
main(int argc,char ** argv)631 main (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\
687 Program exits with return code 0 if all frames were shown without \
688 any errors.  If some frames were shown, but there were some non-fatal \
689 errors, possibly causing an incomplete backtrace, the program exits \
690 with return code 1.  If no frames could be shown, or a fatal error \
691 occurred the program exits with return code 2.  If the program was \
692 invoked 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