LCOV - code coverage report
Current view: top level - src - stack.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 213 306 69.6 %
Date: 2017-08-02 15:24:56 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 <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             : #include <printversion.h>
      34             : 
      35             : /* Name and version of program.  */
      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
     110          47 : get_addr_width (Dwfl_Module *mod)
     111             : {
     112             :   // Try to find the address wide if possible.
     113             :   static int width = 0;
     114          47 :   if (width == 0 && mod)
     115             :     {
     116             :       Dwarf_Addr bias;
     117          13 :       Elf *elf = dwfl_module_getelf (mod, &bias);
     118          13 :       if (elf)
     119             :         {
     120             :           GElf_Ehdr ehdr_mem;
     121          13 :           GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
     122          13 :           if (ehdr)
     123          13 :             width = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16;
     124             :         }
     125             :     }
     126          47 :   if (width == 0)
     127           0 :     width = 16;
     128             : 
     129          47 :   return width;
     130             : }
     131             : 
     132             : static int
     133           0 : 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           0 :   Elf *elf = dwfl_module_getelf (mod, &bias);
     140           0 :   Dwarf *dwarf = dwfl_module_getdwarf (mod, &bias);
     141             : 
     142             :   Dwarf_Addr end;
     143             :   const char *mainfile;
     144             :   const char *debugfile;
     145           0 :   const char *modname = dwfl_module_info (mod, NULL, NULL, &end, NULL,
     146             :                                           NULL, &mainfile, &debugfile);
     147           0 :   assert (strcmp (modname, name) == 0);
     148             : 
     149           0 :   int width = get_addr_width (mod);
     150           0 :   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           0 :   int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
     156           0 :   if (id_len > 0)
     157             :     {
     158             :       printf ("  [");
     159             :       do
     160           0 :         printf ("%02" PRIx8, *id++);
     161           0 :       while (--id_len > 0);
     162             :       printf ("]\n");
     163             :     }
     164             : 
     165           0 :   if (elf != NULL)
     166           0 :     printf ("  %s\n", mainfile != NULL ? mainfile : "-");
     167           0 :   if (dwarf != NULL)
     168           0 :     printf ("  %s\n", debugfile != NULL ? debugfile : "-");
     169             : 
     170           0 :   return DWARF_CB_OK;
     171             : }
     172             : 
     173             : static int
     174          35 : frame_callback (Dwfl_Frame *state, void *arg)
     175             : {
     176          35 :   struct frames *frames = (struct frames *) arg;
     177          35 :   int nr = frames->frames;
     178          35 :   if (! dwfl_frame_pc (state, &frames->frame[nr].pc,
     179          35 :                        &frames->frame[nr].isactivation))
     180             :     return -1;
     181             : 
     182          35 :   frames->frames++;
     183          35 :   if (frames->frames == maxframes)
     184             :     return DWARF_CB_ABORT;
     185             : 
     186          28 :   if (frames->frames == frames->allocated)
     187             :     {
     188           0 :       frames->allocated *= 2;
     189           0 :       frames->frame = realloc (frames->frame,
     190           0 :                                sizeof (struct frame) * frames->allocated);
     191           0 :       if (frames->frame == NULL)
     192           0 :         error (EXIT_BAD, errno, "realloc frames.frame");
     193             :     }
     194             : 
     195             :   return DWARF_CB_OK;
     196             : }
     197             : 
     198             : static const char*
     199          28 : die_name (Dwarf_Die *die)
     200             : {
     201             :   Dwarf_Attribute attr;
     202             :   const char *name;
     203          28 :   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          28 :   if (name == NULL)
     210          24 :     name = dwarf_diename (die);
     211             : 
     212          28 :   return name;
     213             : }
     214             : 
     215             : static void
     216          47 : 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          47 :   int width = get_addr_width (mod);
     222          47 :   printf ("#%-2u 0x%0*" PRIx64, nr, width, (uint64_t) pc);
     223             : 
     224          47 :   if (show_activation)
     225           0 :     printf ("%4s", ! isactivation ? "- 1" : "");
     226             : 
     227          47 :   if (symname != NULL)
     228             :     {
     229             : #ifdef USE_DEMANGLE
     230             :       // Require GNU v3 ABI by the "_Z" prefix.
     231          46 :       if (! show_raw && symname[0] == '_' && symname[1] == 'Z')
     232             :         {
     233           5 :           int status = -1;
     234           5 :           char *dsymname = __cxa_demangle (symname, demangle_buffer,
     235             :                                            &demangle_buffer_len, &status);
     236           5 :           if (status == 0)
     237           5 :             symname = demangle_buffer = dsymname;
     238             :         }
     239             : #endif
     240             :       printf (" %s", symname);
     241             :     }
     242             : 
     243             :   const char* fname;
     244             :   Dwarf_Addr start;
     245          47 :   fname = dwfl_module_info(mod, NULL, &start,
     246             :                            NULL, NULL, NULL, NULL, NULL);
     247          47 :   if (show_module)
     248             :     {
     249           3 :       if (fname != NULL)
     250             :         printf (" - %s", fname);
     251             :     }
     252             : 
     253          47 :   if (show_build_id)
     254             :     {
     255             :       const unsigned char *id;
     256             :       GElf_Addr id_vaddr;
     257           0 :       int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
     258           0 :       if (id_len > 0)
     259             :         {
     260             :           printf ("\n    [");
     261             :           do
     262           0 :             printf ("%02" PRIx8, *id++);
     263           0 :           while (--id_len > 0);
     264           0 :           printf ("]@0x%0" PRIx64 "+0x%" PRIx64,
     265             :                   start, pc_adjusted - start);
     266             :         }
     267             :     }
     268             : 
     269          47 :   if (show_source)
     270             :     {
     271             :       int line, col;
     272             :       const char* sname;
     273          18 :       line = col = -1;
     274          18 :       sname = NULL;
     275          18 :       if (die != NULL)
     276             :         {
     277             :           Dwarf_Files *files;
     278           8 :           if (dwarf_getsrcfiles (cudie, &files, NULL) == 0)
     279             :             {
     280             :               Dwarf_Attribute attr;
     281             :               Dwarf_Word val;
     282           8 :               if (dwarf_formudata (dwarf_attr (die, DW_AT_call_file, &attr),
     283             :                                    &val) == 0)
     284             :                 {
     285           8 :                   sname = dwarf_filesrc (files, val, NULL, NULL);
     286           8 :                   if (dwarf_formudata (dwarf_attr (die, DW_AT_call_line,
     287             :                                                    &attr), &val) == 0)
     288             :                     {
     289           8 :                       line = val;
     290           8 :                       if (dwarf_formudata (dwarf_attr (die, DW_AT_call_column,
     291             :                                                        &attr), &val) == 0)
     292           0 :                         col = val;
     293             :                     }
     294             :                 }
     295             :             }
     296             :         }
     297             :       else
     298             :         {
     299          10 :           Dwfl_Line *lineobj = dwfl_module_getsrc(mod, pc_adjusted);
     300          10 :           if (lineobj)
     301          10 :             sname = dwfl_lineinfo (lineobj, NULL, &line, &col, NULL, NULL);
     302             :         }
     303             : 
     304          18 :       if (sname != NULL)
     305             :         {
     306          18 :           printf ("\n    %s", sname);
     307          18 :           if (line > 0)
     308             :             {
     309          36 :               printf (":%d", line);
     310          18 :               if (col > 0)
     311           0 :                 printf (":%d", col);
     312             :             }
     313             :         }
     314             :     }
     315          47 :   printf ("\n");
     316          47 : }
     317             : 
     318             : static void
     319           8 : 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           8 :   Dwarf_Die *scopes = NULL;
     324           8 :   int nscopes = dwarf_getscopes_die (die, &scopes);
     325           8 :   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           8 :       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           8 :       Dwarf_Die *last_scope = &scopes[0];
     336          28 :       for (int i = 1; i < nscopes && (maxframes == 0 || *nr < maxframes); i++)
     337             :         {
     338          24 :           Dwarf_Die *scope = &scopes[i];
     339          24 :           int tag = dwarf_tag (scope);
     340          48 :           if (tag != DW_TAG_inlined_subroutine
     341          24 :               && tag != DW_TAG_entry_point
     342          12 :               && tag != DW_TAG_subprogram)
     343           8 :             continue;
     344             : 
     345          16 :           symname = die_name (scope);
     346          16 :           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          16 :           if (tag == DW_TAG_subprogram)
     351             :             break;
     352             : 
     353             :           last_scope = scope;
     354             :         }
     355             :     }
     356           8 :   free (scopes);
     357           8 : }
     358             : 
     359             : static void
     360          13 : print_frames (struct frames *frames, pid_t tid, int dwflerr, const char *what)
     361             : {
     362          13 :   if (frames->frames > 0)
     363          13 :     frames_shown = true;
     364             : 
     365          13 :   printf ("TID %d:\n", tid);
     366          13 :   int frame_nr = 0;
     367          57 :   for (int nr = 0; nr < frames->frames && (maxframes == 0
     368          66 :                                            || frame_nr < maxframes); nr++)
     369             :     {
     370          31 :       Dwarf_Addr pc = frames->frame[nr].pc;
     371          31 :       bool isactivation = frames->frame[nr].isactivation;
     372          31 :       Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
     373             : 
     374             :       /* Get PC->SYMNAME.  */
     375          31 :       Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
     376          31 :       const char *symname = NULL;
     377             :       Dwarf_Die die_mem;
     378          31 :       Dwarf_Die *die = NULL;
     379          31 :       Dwarf_Die *cudie = NULL;
     380          31 :       if (mod && ! show_quiet)
     381             :         {
     382          31 :           if (show_debugname)
     383             :             {
     384          12 :               Dwarf_Addr bias = 0;
     385          12 :               Dwarf_Die *scopes = NULL;
     386          12 :               cudie = dwfl_module_addrdie (mod, pc_adjusted, &bias);
     387          12 :               int nscopes = dwarf_getscopes (cudie, pc_adjusted - bias,
     388             :                                              &scopes);
     389             : 
     390             :               /* Find the first function-like DIE with a name in scope.  */
     391          24 :               for (int i = 0; symname == NULL && i < nscopes; i++)
     392             :                 {
     393          12 :                   Dwarf_Die *scope = &scopes[i];
     394          12 :                   int tag = dwarf_tag (scope);
     395          24 :                   if (tag == DW_TAG_subprogram
     396          12 :                       || tag == DW_TAG_inlined_subroutine
     397           0 :                       || tag == DW_TAG_entry_point)
     398          12 :                     symname = die_name (scope);
     399             : 
     400          12 :                   if (symname != NULL)
     401             :                     {
     402          12 :                       die_mem = *scope;
     403          12 :                       die = &die_mem;
     404             :                     }
     405             :                 }
     406          12 :               free (scopes);
     407             :             }
     408             : 
     409          31 :           if (symname == NULL)
     410          19 :             symname = dwfl_module_addrname (mod, pc_adjusted);
     411             :         }
     412             : 
     413          31 :       if (show_inlines && die != NULL)
     414           8 :         print_inline_frames (&frame_nr, pc, isactivation, pc_adjusted, mod,
     415             :                              symname, cudie, die);
     416             :       else
     417          23 :         print_frame (frame_nr++, pc, isactivation, pc_adjusted, mod, symname,
     418             :                      NULL, NULL);
     419             :     }
     420             : 
     421          13 :   if (frames->frames > 0 && frame_nr == maxframes)
     422          11 :     error (0, 0, "tid %d: shown max number of frames "
     423             :            "(%d, use -n 0 for unlimited)", tid, maxframes);
     424           2 :   else if (dwflerr != 0)
     425             :     {
     426           1 :       if (frames->frames > 0)
     427             :         {
     428           1 :           unsigned nr = frames->frames - 1;
     429           1 :           Dwarf_Addr pc = frames->frame[nr].pc;
     430           1 :           bool isactivation = frames->frame[nr].isactivation;
     431           1 :           Dwarf_Addr pc_adjusted = pc - (isactivation ? 0 : 1);
     432           1 :           Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
     433           1 :           const char *mainfile = NULL;
     434           1 :           const char *modname = dwfl_module_info (mod, NULL, NULL, NULL, NULL,
     435             :                                                   NULL, &mainfile, NULL);
     436           1 :           if (modname == NULL || modname[0] == '\0')
     437             :             {
     438           0 :               if (mainfile != NULL)
     439           0 :                 modname = mainfile;
     440             :               else
     441             :                 modname = "<unknown>";
     442             :             }
     443           2 :           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           0 :         error (0, 0, "%s tid %d: %s", what, tid, 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 %d: %s", pid,
     579             :                    dwfl_errmsg (-1));
     580           1 :           else if (err > 0)
     581           0 :             error (EXIT_BAD, err, "dwfl_linux_proc_report pid %d", pid);
     582             :         }
     583             : 
     584          13 :       if (core != NULL)
     585             :         {
     586          12 :           dwfl = dwfl_begin (&core_callbacks);
     587          12 :           if (dwfl == NULL)
     588           0 :             error (EXIT_BAD, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
     589          12 :           if (dwfl_core_file_report (dwfl, core, exec) < 0)
     590           0 :             error (EXIT_BAD, 0, "dwfl_core_file_report: %s", dwfl_errmsg (-1));
     591             :         }
     592             : 
     593          13 :       if (dwfl_report_end (dwfl, NULL, NULL) != 0)
     594           0 :         error (EXIT_BAD, 0, "dwfl_report_end: %s", dwfl_errmsg (-1));
     595             : 
     596          13 :       if (pid != 0)
     597             :         {
     598           1 :           int err = dwfl_linux_proc_attach (dwfl, pid, false);
     599           1 :           if (err < 0)
     600           0 :             error (EXIT_BAD, 0, "dwfl_linux_proc_attach pid %d: %s", pid,
     601             :                    dwfl_errmsg (-1));
     602           1 :           else if (err > 0)
     603           0 :             error (EXIT_BAD, err, "dwfl_linux_proc_attach pid %d", pid);
     604             :         }
     605             : 
     606          13 :       if (core != NULL)
     607             :         {
     608          12 :           if (dwfl_core_file_attach (dwfl, core) < 0)
     609           0 :             error (EXIT_BAD, 0, "dwfl_core_file_report: %s", dwfl_errmsg (-1));
     610             :         }
     611             : 
     612             :       /* Makes sure we are properly attached.  */
     613          13 :       if (dwfl_pid (dwfl) < 0)
     614           0 :         error (EXIT_BAD, 0, "dwfl_pid: %s\n", dwfl_errmsg (-1));
     615             :       break;
     616             : 
     617             :     default:
     618             :       return ARGP_ERR_UNKNOWN;
     619             :     }
     620             :   return 0;
     621             : }
     622             : 
     623             : int
     624          13 : main (int argc, char **argv)
     625             : {
     626             :   /* We use no threads here which can interfere with handling a stream.  */
     627          13 :   __fsetlocking (stdin, FSETLOCKING_BYCALLER);
     628          13 :   __fsetlocking (stdout, FSETLOCKING_BYCALLER);
     629          13 :   __fsetlocking (stderr, FSETLOCKING_BYCALLER);
     630             : 
     631             :   /* Set locale.  */
     632          13 :   (void) setlocale (LC_ALL, "");
     633             : 
     634          13 :   const struct argp_option options[] =
     635             :     {
     636             :       { NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
     637             :       { "pid", 'p', "PID", 0,
     638             :         N_("Show stack of process PID"), 0 },
     639             :       { "core", OPT_COREFILE, "COREFILE", 0,
     640             :         N_("Show stack found in COREFILE"), 0 },
     641             :       {  "executable", 'e', "EXEC", 0, N_("(optional) EXECUTABLE that produced COREFILE"), 0 },
     642             :       { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
     643             :         N_("Search path for separate debuginfo files"), 0 },
     644             : 
     645             :       { NULL, 0, NULL, 0, N_("Output selection options:"), 0 },
     646             :       { "activation",  'a', NULL, 0,
     647             :         N_("Additionally show frame activation"), 0 },
     648             :       { "debugname",  'd', NULL, 0,
     649             :         N_("Additionally try to lookup DWARF debuginfo name for frame address"),
     650             :         0 },
     651             :       { "inlines",  'i', NULL, 0,
     652             :         N_("Additionally show inlined function frames using DWARF debuginfo if available (implies -d)"), 0 },
     653             :       { "module",  'm', NULL, 0,
     654             :         N_("Additionally show module file information"), 0 },
     655             :       { "source",  's', NULL, 0,
     656             :         N_("Additionally show source file information"), 0 },
     657             :       { "verbose", 'v', NULL, 0,
     658             :         N_("Show all additional information (activation, debugname, inlines, module and source)"), 0 },
     659             :       { "quiet", 'q', NULL, 0,
     660             :         N_("Do not resolve address to function symbol name"), 0 },
     661             :       { "raw", 'r', NULL, 0,
     662             :         N_("Show raw function symbol names, do not try to demangle names"), 0 },
     663             :       { "build-id",  'b', NULL, 0,
     664             :         N_("Show module build-id, load address and pc offset"), 0 },
     665             :       { NULL, '1', NULL, 0,
     666             :         N_("Show the backtrace of only one thread"), 0 },
     667             :       { NULL, 'n', "MAXFRAMES", 0,
     668             :         N_("Show at most MAXFRAMES per thread (default 256, use 0 for unlimited)"), 0 },
     669             :       { "list-modules", 'l', NULL, 0,
     670             :         N_("Show module memory map with build-id, elf and debug files detected"), 0 },
     671             :       { NULL, 0, NULL, 0, NULL, 0 }
     672             :     };
     673             : 
     674          13 :   const struct argp argp =
     675             :     {
     676             :       .options = options,
     677             :       .parser = parse_opt,
     678             :       .doc = N_("Print a stack for each thread in a process or core file.\v\
     679             : Program exits with return code 0 if all frames were shown without \
     680             : any errors.  If some frames were shown, but there were some non-fatal \
     681             : errors, possibly causing an incomplete backtrace, the program exits \
     682             : with return code 1.  If no frames could be shown, or a fatal error \
     683             : occured the program exits with return code 2.  If the program was \
     684             : invoked with bad or missing arguments it will exit with return code 64.")
     685             :     };
     686             : 
     687          13 :   argp_parse (&argp, argc, argv, 0, NULL, NULL);
     688             : 
     689          13 :   if (show_modules)
     690             :     {
     691           0 :       printf ("PID %d - %s module memory map\n", dwfl_pid (dwfl),
     692           0 :               pid != 0 ? "process" : "core");
     693           0 :       if (dwfl_getmodules (dwfl, module_callback, NULL, 0) != 0)
     694           0 :         error (EXIT_BAD, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
     695             :     }
     696             : 
     697             :   struct frames frames;
     698             :   /* When maxframes is zero, then 2048 is just the initial allocation
     699             :      that will be increased using realloc in framecallback ().  */
     700          13 :   frames.allocated = maxframes == 0 ? 2048 : maxframes;
     701          13 :   frames.frames = 0;
     702          13 :   frames.frame = malloc (sizeof (struct frame) * frames.allocated);
     703          13 :   if (frames.frame == NULL)
     704           0 :     error (EXIT_BAD, errno, "malloc frames.frame");
     705             : 
     706          13 :   if (show_one_tid)
     707             :     {
     708           0 :       int err = 0;
     709           0 :       switch (dwfl_getthread_frames (dwfl, pid, frame_callback, &frames))
     710             :         {
     711             :         case DWARF_CB_OK:
     712             :         case DWARF_CB_ABORT:
     713             :           break;
     714           0 :         case -1:
     715           0 :           err = dwfl_errno ();
     716           0 :           break;
     717           0 :         default:
     718           0 :           abort ();
     719             :         }
     720           0 :       print_frames (&frames, pid, err, "dwfl_getthread_frames");
     721             :     }
     722             :   else
     723             :     {
     724          26 :       printf ("PID %d - %s\n", dwfl_pid (dwfl), pid != 0 ? "process" : "core");
     725          13 :       switch (dwfl_getthreads (dwfl, thread_callback, &frames))
     726             :         {
     727             :         case DWARF_CB_OK:
     728             :         case DWARF_CB_ABORT:
     729             :           break;
     730           0 :         case -1:
     731           0 :           error (0, 0, "dwfl_getthreads: %s", dwfl_errmsg (-1));
     732             :           break;
     733           0 :         default:
     734           0 :           abort ();
     735             :         }
     736             :     }
     737          13 :   free (frames.frame);
     738          13 :   dwfl_end (dwfl);
     739             : 
     740          13 :   if (core != NULL)
     741          12 :     elf_end (core);
     742             : 
     743          13 :   if (core_fd != -1)
     744          12 :     close (core_fd);
     745             : 
     746             : #ifdef USE_DEMANGLE
     747          13 :   free (demangle_buffer);
     748             : #endif
     749             : 
     750          13 :   if (! frames_shown)
     751             :     error (EXIT_BAD, 0, N_("Couldn't show any frames."));
     752             : 
     753          13 :   return error_message_count != 0 ? EXIT_ERROR : EXIT_OK;
     754             : }

Generated by: LCOV version 1.12