LCOV - code coverage report
Current view: top level - src - srcfiles.cxx (source / functions) Hit Total Coverage
Test: elfutils-0.189 Lines: 72 76 94.7 %
Date: 2023-11-03 14:40:44 Functions: 3 3 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 50 79 63.3 %

           Branch data     Line data    Source code
       1                 :            : /* Print the source files of a given ELF file.
       2                 :            :    Copyright (C) 2023 Red Hat, Inc.
       3                 :            :    This file is part of elfutils.
       4                 :            :    Written by Housam Alamour <alamourh@redhat.com>.
       5                 :            : 
       6                 :            :    This file is free software; you can redistribute it and/or modify
       7                 :            :    it under the terms of the GNU General Public License as published by
       8                 :            :    the Free Software Foundation; either version 3 of the License, or
       9                 :            :    (at your option) any later version.
      10                 :            : 
      11                 :            :    elfutils is distributed in the hope that it will be useful, but
      12                 :            :    WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14                 :            :    GNU General Public License for more details.
      15                 :            : 
      16                 :            :    You should have received a copy of the GNU General Public License
      17                 :            :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      18                 :            : 
      19                 :            : #include "printversion.h"
      20                 :            : #include <dwarf.h>
      21                 :            : #include <argp.h>
      22                 :            : #include <cstring>
      23                 :            : #include <set>
      24                 :            : #include <string>
      25                 :            : #include <cassert>
      26                 :            : #include <config.h>
      27                 :            : 
      28                 :            : #include <libdwfl.h>
      29                 :            : #include <fcntl.h>
      30                 :            : #include <iostream>
      31                 :            : #include <libdw.h>
      32                 :            : 
      33                 :            : using namespace std;
      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                 :            : /* Definitions of arguments for argp functions.  */
      42                 :            : static const struct argp_option options[] =
      43                 :            : {
      44                 :            :   { NULL, 0, NULL, OPTION_DOC, N_("Output options:"), 1 },
      45                 :            :   { "null", '0', NULL, 0,
      46                 :            :     N_ ("Separate items by a null instead of a newline."), 0 },
      47                 :            :   { "verbose", 'v', NULL, 0,
      48                 :            :     N_ ("Increase verbosity of logging messages."), 0 },
      49                 :            :   { "cu-only", 'c', NULL, 0, N_ ("Only list the CU names."), 0 },
      50                 :            :   { NULL, 0, NULL, 0, NULL, 0 }
      51                 :            : };
      52                 :            : 
      53                 :            : /* Short description of program.  */
      54                 :            : static const char doc[] = N_("Lists the source files of a DWARF/ELF file. The default input is the file 'a.out'.");
      55                 :            : 
      56                 :            : /* Strings for arguments in help texts.  */
      57                 :            : static const char args_doc[] = N_("INPUT");
      58                 :            : 
      59                 :            : /* Prototype for option handler.  */
      60                 :            : static error_t parse_opt (int key, char *arg, struct argp_state *state);
      61                 :            : 
      62                 :            : static struct argp_child argp_children[2]; /* [0] is set in main.  */
      63                 :            : 
      64                 :            : /* Data structure to communicate with argp functions.  */
      65                 :            : static const struct argp argp =
      66                 :            : {
      67                 :            :   options, parse_opt, args_doc, doc, argp_children, NULL, NULL
      68                 :            : };
      69                 :            : 
      70                 :            : /* Verbose message printing. */
      71                 :            : static bool verbose;
      72                 :            : /* Delimit the output with nulls. */
      73                 :            : static bool null_arg;
      74                 :            : /* Only print compilation unit names. */
      75                 :            : static bool CU_only;
      76                 :            : 
      77                 :            : /* Handle program arguments. */
      78                 :            : static error_t
      79                 :         81 : parse_opt (int key, char *arg, struct argp_state *state)
      80                 :            : {
      81                 :            :   /* Suppress "unused parameter" warning. */
      82                 :         81 :   (void)arg;
      83   [ +  +  +  +  :         81 :   switch (key)
                      + ]
      84                 :            :     {
      85                 :         13 :     case ARGP_KEY_INIT:
      86                 :         13 :       state->child_inputs[0] = state->input;
      87                 :         13 :       break;
      88                 :            : 
      89                 :          6 :     case '0':
      90                 :          6 :       null_arg = true;
      91                 :          6 :       break;
      92                 :            : 
      93                 :          6 :     case 'v':
      94                 :          6 :       verbose = true;
      95                 :          6 :       break;
      96                 :            : 
      97                 :          4 :     case 'c':
      98                 :          4 :       CU_only = true;
      99                 :          4 :       break;
     100                 :            : 
     101                 :            :     default:
     102                 :            :       return ARGP_ERR_UNKNOWN;
     103                 :            :     }
     104                 :            :   return 0;
     105                 :            : }
     106                 :            : 
     107                 :            : 
     108                 :            : /* Global list of collected source files.  Normally, it'll contain
     109                 :            :    the sources of just one named binary, but the '-K' option can cause
     110                 :            :    multiple dwfl modules to be loaded, thus listed.   */
     111                 :            :    set<string> debug_sourcefiles;
     112                 :            : 
     113                 :            : static int
     114                 :         25 : collect_sourcefiles (Dwfl_Module *dwflmod,
     115                 :            :                      void **userdata __attribute__ ((unused)),
     116                 :            :                      const char *name __attribute__ ((unused)),
     117                 :            :                      Dwarf_Addr base __attribute__ ((unused)),
     118                 :            :                      void *arg __attribute__ ((unused)))
     119                 :            : {
     120                 :         25 :   Dwarf *dbg;
     121                 :         25 :   Dwarf_Addr bias; /* ignored - for addressing purposes only  */
     122                 :            : 
     123                 :         25 :   dbg = dwfl_module_getdwarf (dwflmod, &bias);
     124                 :            : 
     125                 :         25 :   Dwarf_Off offset = 0;
     126                 :         25 :   Dwarf_Off old_offset;
     127                 :         25 :   size_t hsize;
     128                 :            : 
     129                 :            :   /* Traverse all CUs of this module.  */
     130         [ +  + ]:      11385 :   while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL, NULL) == 0)
     131                 :            :     {
     132                 :      11360 :       Dwarf_Die cudie_mem;
     133                 :      11360 :       Dwarf_Die *cudie = dwarf_offdie (dbg, old_offset + hsize, &cudie_mem);
     134                 :            : 
     135         [ -  + ]:      11360 :       if (cudie == NULL)
     136                 :          0 :         continue;
     137                 :            : 
     138         [ -  + ]:      11360 :       const char *cuname = dwarf_diename (cudie) ?: "<unknown>";
     139                 :      11360 :       Dwarf_Files *files;
     140                 :      11360 :       size_t nfiles;
     141         [ -  + ]:      11360 :       if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0)
     142                 :          0 :         continue;
     143                 :            : 
     144                 :            :       /* extract DW_AT_comp_dir to resolve relative file names  */
     145                 :      11360 :       const char *comp_dir = "";
     146                 :      11360 :       const char *const *dirs;
     147                 :      11360 :       size_t ndirs;
     148                 :            : 
     149   [ +  -  -  + ]:      11360 :       if (dwarf_getsrcdirs (files, &dirs, &ndirs) == 0 && dirs[0] != NULL)
     150                 :            :         comp_dir = dirs[0];
     151                 :          0 :       if (comp_dir == NULL)
     152                 :            :         comp_dir = "";
     153                 :            : 
     154         [ +  + ]:      11360 :       if (verbose)
     155                 :       5532 :         std::clog << "searching for sources for cu=" << cuname
     156                 :       5532 :                   << " comp_dir=" << comp_dir << " #files=" << nfiles
     157                 :       5532 :                   << " #dirs=" << ndirs << endl;
     158                 :            : 
     159         [ +  + ]:     168123 :       for (size_t f = 1; f < nfiles; f++)
     160                 :            :         {
     161                 :     156763 :           const char *hat;
     162         [ +  + ]:     156763 :           if (CU_only)
     163                 :            :           {
     164   [ +  -  -  + ]:      19116 :             if (strcmp(cuname, "<unknown>") == 0 || strcmp(cuname, "<artificial>") == 0 )
     165                 :       1587 :               continue;
     166                 :            :             hat = cuname;
     167                 :            :           }
     168                 :            :           else
     169                 :     137647 :             hat = dwarf_filesrc (files, f, NULL, NULL);
     170                 :            : 
     171         [ -  + ]:     137647 :           if (hat == NULL)
     172                 :          0 :             continue;
     173                 :            : 
     174         [ +  + ]:     313526 :           if (string(hat).find("<built-in>")
     175         [ +  + ]:     156763 :               != std::string::npos) /* gcc intrinsics, don't bother record  */
     176                 :       1587 :             continue;
     177                 :            : 
     178         [ +  + ]:     155176 :           string waldo;
     179         [ +  + ]:     155176 :           if (hat[0] == '/') /* absolute */
     180   [ +  -  -  + ]:      21796 :             waldo = (string (hat));
     181         [ +  - ]:     133380 :           else if (comp_dir[0] != '\0') /* comp_dir relative */
     182   [ +  -  +  -  :     248728 :             waldo = (string (comp_dir) + string ("/") + string (hat));
          +  -  +  -  +  
          -  -  +  -  +  
          -  +  -  +  +  
          +  -  -  -  -  
                   -  - ]
     183         [ +  - ]:     155176 :           debug_sourcefiles.insert (waldo);
     184                 :     155176 :         }
     185                 :            :     }
     186                 :            : 
     187                 :         25 :   return DWARF_CB_OK;
     188                 :            : }
     189                 :            : 
     190                 :            : 
     191                 :            : int
     192                 :         13 : main (int argc, char *argv[])
     193                 :            : {
     194                 :         13 :   int remaining;
     195                 :            : 
     196                 :            :   /* Parse and process arguments.  This includes opening the modules.  */
     197                 :         13 :   argp_children[0].argp = dwfl_standard_argp ();
     198                 :         13 :   argp_children[0].group = 1;
     199                 :            : 
     200                 :         13 :   Dwfl *dwfl = NULL;
     201                 :         13 :   (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
     202         [ -  + ]:         13 :   assert (dwfl != NULL);
     203                 :            :   /* Process all loaded modules - probably just one, except if -K or -p is used. */
     204                 :         13 :   (void) dwfl_getmodules (dwfl, &collect_sourcefiles, NULL, 0);
     205                 :            : 
     206         [ +  - ]:         13 :   if (!debug_sourcefiles.empty ())
     207         [ +  + ]:      22363 :     for (const string &element : debug_sourcefiles)
     208                 :            :       {
     209                 :      22350 :         std::cout << element;
     210         [ +  + ]:      22350 :         if (null_arg)
     211                 :      10906 :           std::cout << '\0';
     212                 :            :         else
     213                 :      11444 :           std::cout << '\n';
     214                 :            :       }
     215                 :            : 
     216                 :         13 :   dwfl_end (dwfl);
     217                 :         13 :   return 0;
     218                 :            : }

Generated by: LCOV version 1.16