LCOV - code coverage report
Current view: top level - src - stack.c (source / functions) Hit Total Coverage
Test: elfutils-0.175 Lines: 214 307 69.7 %
Date: 2018-11-16 13:02:39 Functions: 9 10 90.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13