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

Generated by: LCOV version 1.13