LCOV - code coverage report
Current view: top level - src - stack.c (source / functions) Hit Total Coverage
Test: elfutils-0.173 Lines: 200 280 71.4 %
Date: 2018-06-29 23:49:12 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             :                                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             :   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             :           printf ("\n    %s", sname);
     307          18 :           if (line > 0)
     308             :             {
     309          18 :               printf (":%d", line);
     310          18 :               if (col > 0)
     311           0 :                 printf (":%d", col);
     312             :             }
     313             :         }
     314             :     }
     315             :   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 %lld:\n", (long long) 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 %lld: shown max number of frames "
     423             :            "(%d, use -n 0 for unlimited)", (long long) 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           1 :           error (0, 0, "%s tid %lld at 0x%" PRIx64 " in %s: %s", what,
     444             :                  (long long) tid, pc_adjusted, modname, dwfl_errmsg (dwflerr));
     445             :         }
     446             :       else
     447           0 :         error (0, 0, "%s tid %lld: %s", what, (long long) tid,
     448             :                dwfl_errmsg (dwflerr));
     449             :     }
     450          13 : }
     451             : 
     452             : static int
     453          13 : thread_callback (Dwfl_Thread *thread, void *thread_arg)
     454             : {
     455          13 :   struct frames *frames = (struct frames *) thread_arg;
     456          13 :   pid_t tid = dwfl_thread_tid (thread);
     457          13 :   int err = 0;
     458          13 :   frames->frames = 0;
     459          13 :   switch (dwfl_thread_getframes (thread, frame_callback, thread_arg))
     460             :     {
     461             :     case DWARF_CB_OK:
     462             :     case DWARF_CB_ABORT:
     463             :       break;
     464             :     case -1:
     465           5 :       err = dwfl_errno ();
     466           5 :       break;
     467             :     default:
     468           0 :       abort ();
     469             :     }
     470          13 :   print_frames (frames, tid, err, "dwfl_thread_getframes");
     471          13 :   return DWARF_CB_OK;
     472             : }
     473             : 
     474             : static error_t
     475         117 : parse_opt (int key, char *arg __attribute__ ((unused)),
     476             :            struct argp_state *state)
     477             : {
     478         117 :   switch (key)
     479             :     {
     480             :     case 'p':
     481           1 :       pid = atoi (arg);
     482           1 :       if (pid == 0)
     483           0 :         argp_error (state, N_("-p PID should be a positive process id."));
     484             :       break;
     485             : 
     486             :     case OPT_COREFILE:
     487          12 :       core_fd = open (arg, O_RDONLY);
     488          12 :       if (core_fd < 0)
     489           0 :         error (EXIT_BAD, errno, N_("Cannot open core file '%s'"), arg);
     490          12 :       elf_version (EV_CURRENT);
     491          12 :       core = elf_begin (core_fd, ELF_C_READ_MMAP, NULL);
     492          12 :       if (core == NULL)
     493           0 :         error (EXIT_BAD, 0, "core '%s' elf_begin: %s", arg, elf_errmsg(-1));
     494             :       break;
     495             : 
     496             :     case 'e':
     497          12 :       exec = arg;
     498          12 :       break;
     499             : 
     500             :     case OPT_DEBUGINFO:
     501           0 :       debuginfo_path = arg;
     502           0 :       break;
     503             : 
     504             :     case 'm':
     505           1 :       show_module = true;
     506           1 :       break;
     507             : 
     508             :     case 's':
     509           5 :       show_source = true;
     510           5 :       break;
     511             : 
     512             :     case 'a':
     513           0 :       show_activation = true;
     514           0 :       break;
     515             : 
     516             :     case 'd':
     517           2 :       show_debugname = true;
     518           2 :       break;
     519             : 
     520             :     case 'i':
     521           4 :       show_inlines = show_debugname = true;
     522           4 :       break;
     523             : 
     524             :     case 'v':
     525           0 :       show_activation = show_source = show_module = show_debugname = true;
     526           0 :       show_inlines = true;
     527           0 :       break;
     528             : 
     529             :     case 'b':
     530           0 :       show_build_id = true;
     531           0 :       break;
     532             : 
     533             :     case 'q':
     534           0 :       show_quiet = true;
     535           0 :       break;
     536             : 
     537             :     case 'r':
     538           4 :       show_raw = true;
     539           4 :       break;
     540             : 
     541             :     case '1':
     542           0 :       show_one_tid = true;
     543           0 :       break;
     544             : 
     545             :     case 'n':
     546          11 :       maxframes = atoi (arg);
     547          11 :       if (maxframes < 0)
     548             :         {
     549           0 :           argp_error (state, N_("-n MAXFRAMES should be 0 or higher."));
     550           0 :           return EINVAL;
     551             :         }
     552             :       break;
     553             : 
     554             :     case 'l':
     555           0 :       show_modules = true;
     556           0 :       break;
     557             : 
     558             :     case ARGP_KEY_END:
     559          13 :       if (core == NULL && exec != NULL)
     560           0 :         argp_error (state,
     561             :                     N_("-e EXEC needs a core given by --core."));
     562             : 
     563          13 :       if (pid == 0 && show_one_tid == true)
     564           0 :         argp_error (state,
     565             :                     N_("-1 needs a thread id given by -p."));
     566             : 
     567          13 :       if ((pid == 0 && core == NULL) || (pid != 0 && core != NULL))
     568           0 :         argp_error (state,
     569             :                     N_("One of -p PID or --core COREFILE should be given."));
     570             : 
     571          13 :       if (pid != 0)
     572             :         {
     573           1 :           dwfl = dwfl_begin (&proc_callbacks);
     574           1 :           if (dwfl == NULL)
     575           0 :             error (EXIT_BAD, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
     576             : 
     577           1 :           int err = dwfl_linux_proc_report (dwfl, pid);
     578           1 :           if (err < 0)
     579           0 :             error (EXIT_BAD, 0, "dwfl_linux_proc_report pid %lld: %s",
     580             :                    (long long) pid, dwfl_errmsg (-1));
     581           1 :           else if (err > 0)
     582           0 :             error (EXIT_BAD, err, "dwfl_linux_proc_report pid %lld",
     583             :                    (long long) pid);
     584             :         }
     585             : 
     586          13 :       if (core != NULL)
     587             :         {
     588          12 :           dwfl = dwfl_begin (&core_callbacks);
     589          12 :           if (dwfl == NULL)
     590           0 :             error (EXIT_BAD, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
     591          12 :           if (dwfl_core_file_report (dwfl, core, exec) < 0)
     592           0 :             error (EXIT_BAD, 0, "dwfl_core_file_report: %s", dwfl_errmsg (-1));
     593             :         }
     594             : 
     595          13 :       if (dwfl_report_end (dwfl, NULL, NULL) != 0)
     596           0 :         error (EXIT_BAD, 0, "dwfl_report_end: %s", dwfl_errmsg (-1));
     597             : 
     598          13 :       if (pid != 0)
     599             :         {
     600           1 :           int err = dwfl_linux_proc_attach (dwfl, pid, false);
     601           1 :           if (err < 0)
     602           0 :             error (EXIT_BAD, 0, "dwfl_linux_proc_attach pid %lld: %s",
     603             :                    (long long) pid, dwfl_errmsg (-1));
     604           1 :           else if (err > 0)
     605           0 :             error (EXIT_BAD, err, "dwfl_linux_proc_attach pid %lld",
     606             :                    (long long) pid);
     607             :         }
     608             : 
     609          13 :       if (core != NULL)
     610             :         {
     611          12 :           if (dwfl_core_file_attach (dwfl, core) < 0)
     612           0 :             error (EXIT_BAD, 0, "dwfl_core_file_report: %s", dwfl_errmsg (-1));
     613             :         }
     614             : 
     615             :       /* Makes sure we are properly attached.  */
     616          13 :       if (dwfl_pid (dwfl) < 0)
     617           0 :         error (EXIT_BAD, 0, "dwfl_pid: %s\n", dwfl_errmsg (-1));
     618             :       break;
     619             : 
     620             :     default:
     621             :       return ARGP_ERR_UNKNOWN;
     622             :     }
     623             :   return 0;
     624             : }
     625             : 
     626             : int
     627          13 : main (int argc, char **argv)
     628             : {
     629             :   /* We use no threads here which can interfere with handling a stream.  */
     630          13 :   __fsetlocking (stdin, FSETLOCKING_BYCALLER);
     631          13 :   __fsetlocking (stdout, FSETLOCKING_BYCALLER);
     632          13 :   __fsetlocking (stderr, FSETLOCKING_BYCALLER);
     633             : 
     634             :   /* Set locale.  */
     635          13 :   (void) setlocale (LC_ALL, "");
     636             : 
     637          13 :   const struct argp_option options[] =
     638             :     {
     639             :       { NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
     640             :       { "pid", 'p', "PID", 0,
     641             :         N_("Show stack of process PID"), 0 },
     642             :       { "core", OPT_COREFILE, "COREFILE", 0,
     643             :         N_("Show stack found in COREFILE"), 0 },
     644             :       {  "executable", 'e', "EXEC", 0, N_("(optional) EXECUTABLE that produced COREFILE"), 0 },
     645             :       { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
     646             :         N_("Search path for separate debuginfo files"), 0 },
     647             : 
     648             :       { NULL, 0, NULL, 0, N_("Output selection options:"), 0 },
     649             :       { "activation",  'a', NULL, 0,
     650             :         N_("Additionally show frame activation"), 0 },
     651             :       { "debugname",  'd', NULL, 0,
     652             :         N_("Additionally try to lookup DWARF debuginfo name for frame address"),
     653             :         0 },
     654             :       { "inlines",  'i', NULL, 0,
     655             :         N_("Additionally show inlined function frames using DWARF debuginfo if available (implies -d)"), 0 },
     656             :       { "module",  'm', NULL, 0,
     657             :         N_("Additionally show module file information"), 0 },
     658             :       { "source",  's', NULL, 0,
     659             :         N_("Additionally show source file information"), 0 },
     660             :       { "verbose", 'v', NULL, 0,
     661             :         N_("Show all additional information (activation, debugname, inlines, module and source)"), 0 },
     662             :       { "quiet", 'q', NULL, 0,
     663             :         N_("Do not resolve address to function symbol name"), 0 },
     664             :       { "raw", 'r', NULL, 0,
     665             :         N_("Show raw function symbol names, do not try to demangle names"), 0 },
     666             :       { "build-id",  'b', NULL, 0,
     667             :         N_("Show module build-id, load address and pc offset"), 0 },
     668             :       { NULL, '1', NULL, 0,
     669             :         N_("Show the backtrace of only one thread"), 0 },
     670             :       { NULL, 'n', "MAXFRAMES", 0,
     671             :         N_("Show at most MAXFRAMES per thread (default 256, use 0 for unlimited)"), 0 },
     672             :       { "list-modules", 'l', NULL, 0,
     673             :         N_("Show module memory map with build-id, elf and debug files detected"), 0 },
     674             :       { NULL, 0, NULL, 0, NULL, 0 }
     675             :     };
     676             : 
     677          13 :   const struct argp argp =
     678             :     {
     679             :       .options = options,
     680             :       .parser = parse_opt,
     681             :       .doc = N_("Print a stack for each thread in a process or core file.\n\
     682             : \n\
     683             : Program exits with return code 0 if all frames were shown without \
     684             : any errors.  If some frames were shown, but there were some non-fatal \
     685             : errors, possibly causing an incomplete backtrace, the program exits \
     686             : with return code 1.  If no frames could be shown, or a fatal error \
     687             : occured the program exits with return code 2.  If the program was \
     688             : invoked with bad or missing arguments it will exit with return code 64.")
     689             :     };
     690             : 
     691          13 :   argp_parse (&argp, argc, argv, 0, NULL, NULL);
     692             : 
     693          13 :   if (show_modules)
     694             :     {
     695           0 :       printf ("PID %lld - %s module memory map\n", (long long) dwfl_pid (dwfl),
     696           0 :               pid != 0 ? "process" : "core");
     697           0 :       if (dwfl_getmodules (dwfl, module_callback, NULL, 0) != 0)
     698           0 :         error (EXIT_BAD, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
     699             :     }
     700             : 
     701             :   struct frames frames;
     702             :   /* When maxframes is zero, then 2048 is just the initial allocation
     703             :      that will be increased using realloc in framecallback ().  */
     704          13 :   frames.allocated = maxframes == 0 ? 2048 : maxframes;
     705          13 :   frames.frames = 0;
     706          13 :   frames.frame = malloc (sizeof (struct frame) * frames.allocated);
     707          13 :   if (frames.frame == NULL)
     708           0 :     error (EXIT_BAD, errno, "malloc frames.frame");
     709             : 
     710          13 :   if (show_one_tid)
     711             :     {
     712           0 :       int err = 0;
     713           0 :       switch (dwfl_getthread_frames (dwfl, pid, frame_callback, &frames))
     714             :         {
     715             :         case DWARF_CB_OK:
     716             :         case DWARF_CB_ABORT:
     717             :           break;
     718             :         case -1:
     719           0 :           err = dwfl_errno ();
     720           0 :           break;
     721             :         default:
     722           0 :           abort ();
     723             :         }
     724           0 :       print_frames (&frames, pid, err, "dwfl_getthread_frames");
     725             :     }
     726             :   else
     727             :     {
     728          13 :       printf ("PID %lld - %s\n", (long long) dwfl_pid (dwfl),
     729          13 :               pid != 0 ? "process" : "core");
     730          13 :       switch (dwfl_getthreads (dwfl, thread_callback, &frames))
     731             :         {
     732             :         case DWARF_CB_OK:
     733             :         case DWARF_CB_ABORT:
     734             :           break;
     735             :         case -1:
     736           0 :           error (0, 0, "dwfl_getthreads: %s", dwfl_errmsg (-1));
     737             :           break;
     738             :         default:
     739           0 :           abort ();
     740             :         }
     741             :     }
     742          13 :   free (frames.frame);
     743          13 :   dwfl_end (dwfl);
     744             : 
     745          13 :   if (core != NULL)
     746          12 :     elf_end (core);
     747             : 
     748          13 :   if (core_fd != -1)
     749          12 :     close (core_fd);
     750             : 
     751             : #ifdef USE_DEMANGLE
     752          13 :   free (demangle_buffer);
     753             : #endif
     754             : 
     755          13 :   if (! frames_shown)
     756             :     error (EXIT_BAD, 0, N_("Couldn't show any frames."));
     757             : 
     758          13 :   return error_message_count != 0 ? EXIT_ERROR : EXIT_OK;
     759             : }

Generated by: LCOV version 1.13