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