LCOV - code coverage report
Current view: top level - src - srcfiles.cxx (source / functions) Coverage Total Hit
Test: elfutils-0.193 Lines: 78.8 % 184 145
Test Date: 2025-08-30 14:31:09 Functions: 100.0 % 5 5
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 38.8 % 263 102

             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                 :             : 
      20                 :             : /* In case we have a bad fts we include this before config.h because it
      21                 :             :    can't handle _FILE_OFFSET_BITS.
      22                 :             :    Everything we need here is fine if its declarations just come first.
      23                 :             :    Also, include sys/types.h before fts.  On some systems fts.h is not self
      24                 :             :    contained.  */
      25                 :             : #ifdef BAD_FTS
      26                 :             : #include <sys/types.h>
      27                 :             : #include <fts.h>
      28                 :             : #endif
      29                 :             : 
      30                 :             : #ifdef HAVE_CONFIG_H
      31                 :             : # include <config.h>
      32                 :             : #endif
      33                 :             : 
      34                 :             : #include "printversion.h"
      35                 :             : #include <dwarf.h>
      36                 :             : #include <argp.h>
      37                 :             : #include <cstring>
      38                 :             : #include <set>
      39                 :             : #include <string>
      40                 :             : #include <cassert>
      41                 :             : #include <gelf.h>
      42                 :             : #include <memory>
      43                 :             : 
      44                 :             : #ifdef ENABLE_LIBDEBUGINFOD
      45                 :             : #include "debuginfod.h"
      46                 :             : #endif
      47                 :             : 
      48                 :             : #include <libdwfl.h>
      49                 :             : #include <fcntl.h>
      50                 :             : #include <iostream>
      51                 :             : #include <libdw.h>
      52                 :             : #include <sstream>
      53                 :             : #include <vector>
      54                 :             : 
      55                 :             : /* Libraries for use by the --zip option */
      56                 :             : #ifdef HAVE_LIBARCHIVE
      57                 :             : #include <archive.h>
      58                 :             : #include <archive_entry.h>
      59                 :             : #endif
      60                 :             : 
      61                 :             : /* If fts.h is included before config.h, its indirect inclusions may not
      62                 :             :    give us the right LFS aliases of these functions, so map them manually.  */
      63                 :             : #ifdef BAD_FTS
      64                 :             : #ifdef _FILE_OFFSET_BITS
      65                 :             : #define open open64
      66                 :             : #define fopen fopen64
      67                 :             : #endif
      68                 :             : #else
      69                 :             :   #include <sys/types.h>
      70                 :             :   #include <fts.h>
      71                 :             : #endif
      72                 :             : 
      73                 :             : using namespace std;
      74                 :             : 
      75                 :             : /* Name and version of program.  */
      76                 :             : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
      77                 :             : 
      78                 :             : /* Bug report address.  */
      79                 :             : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
      80                 :             : 
      81                 :             : #ifdef HAVE_LIBARCHIVE
      82                 :             : constexpr size_t BUFFER_SIZE = 8192;
      83                 :             : #endif
      84                 :             : 
      85                 :             : /* Definitions of arguments for argp functions.  */
      86                 :             : static const struct argp_option options[] =
      87                 :             : {
      88                 :             :   { NULL, 0, NULL, OPTION_DOC, N_("Output options:"), 1 },
      89                 :             :   { "null", '0', NULL, 0,
      90                 :             :     N_ ("Separate items by a null instead of a newline."), 0 },
      91                 :             :   { "verbose", 'v', NULL, 0,
      92                 :             :     N_ ("Increase verbosity of logging messages."), 0 },
      93                 :             :   { "cu-only", 'c', NULL, 0, N_("Only list the CU names."), 0 },
      94                 :             :   #ifdef HAVE_LIBARCHIVE
      95                 :             :   { "zip", 'z', NULL, 0, N_("Zip all the source files and send to stdout. "
      96                 :             :     "Cannot be used with the null option"), 0 },
      97                 :             :     #ifdef ENABLE_LIBDEBUGINFOD
      98                 :             :     { "no-backup", 'b', NULL, 0, N_("Disables local source file search when "
      99                 :             :       "debuginfod fails to fetch files. This option is only applicable"
     100                 :             :       "when fetching and zipping files."), 0 },
     101                 :             :     #endif
     102                 :             :   #endif
     103                 :             :   { NULL, 0, NULL, 0, NULL, 0 }
     104                 :             : };
     105                 :             : 
     106                 :             : /* Short description of program.  */
     107                 :             : static const char doc[] = N_("Lists the source files of a DWARF/ELF file.  The default input is the file 'a.out'.");
     108                 :             : 
     109                 :             : /* Strings for arguments in help texts.  */
     110                 :             : static const char args_doc[] = N_("INPUT");
     111                 :             : 
     112                 :             : /* Prototype for option handler.  */
     113                 :             : static error_t parse_opt (int key, char *arg, struct argp_state *state);
     114                 :             : 
     115                 :             : static struct argp_child argp_children[2]; /* [0] is set in main.  */
     116                 :             : 
     117                 :             : /* Data structure to communicate with argp functions.  */
     118                 :             : static const struct argp argp =
     119                 :             : {
     120                 :             :   options, parse_opt, args_doc, doc, argp_children, NULL, NULL
     121                 :             : };
     122                 :             : 
     123                 :             : /* Verbose message printing.  */
     124                 :             : static bool verbose;
     125                 :             : /* Delimit the output with nulls.  */
     126                 :             : static bool null_arg;
     127                 :             : /* Only print compilation unit names.  */
     128                 :             : static bool CU_only;
     129                 :             : #ifdef HAVE_LIBARCHIVE
     130                 :             :   /* Zip all the source files and send to stdout. */
     131                 :             :   static bool zip;
     132                 :             : 
     133                 :             :   #ifdef ENABLE_LIBDEBUGINFOD
     134                 :             :     /* Disables local source file search when debuginfod fails to fetch them.
     135                 :             :        This option is only applicable when fetching and zipping files.*/
     136                 :             :     static bool no_backup;
     137                 :             :   #endif
     138                 :             : #endif
     139                 :             : 
     140                 :             : /* Handle program arguments.  Note null arg and zip
     141                 :             :     cannot be combined due to warnings raised when unzipping.  */
     142                 :             : static error_t
     143                 :         230 : parse_opt (int key, char *arg, struct argp_state *state)
     144                 :             : {
     145                 :             :   /* Suppress "unused parameter" warning.  */
     146                 :         230 :   (void)arg;
     147   [ +  +  +  +  :         230 :   switch (key)
                +  +  + ]
     148                 :             :     {
     149                 :          38 :     case ARGP_KEY_INIT:
     150                 :          38 :       state->child_inputs[0] = state->input;
     151                 :          38 :       break;
     152                 :             : 
     153                 :          12 :     case '0':
     154                 :          12 :       null_arg = true;
     155                 :          12 :       break;
     156                 :             : 
     157                 :          16 :     case 'v':
     158                 :          16 :       verbose = true;
     159                 :          16 :       break;
     160                 :             : 
     161                 :           8 :     case 'c':
     162                 :           8 :       CU_only = true;
     163                 :           8 :       break;
     164                 :             : 
     165                 :             :     #ifdef HAVE_LIBARCHIVE
     166                 :          10 :       case 'z':
     167                 :          10 :       zip = true;
     168                 :          10 :       break;
     169                 :             : 
     170                 :             :       #ifdef ENABLE_LIBDEBUGINFOD
     171                 :           2 :         case 'b':
     172                 :           2 :         no_backup = true;
     173                 :           2 :         break;
     174                 :             :       #endif
     175                 :             :     #endif
     176                 :             : 
     177                 :             :     default:
     178                 :             :       return ARGP_ERR_UNKNOWN;
     179                 :             :     }
     180                 :             :   return 0;
     181                 :             : }
     182                 :             : 
     183                 :             : /* Remove the "/./" , "../" and the preceding directory
     184                 :             :     that some paths include which raise errors during unzip.  */
     185                 :      341836 : string canonicalize_path(string path)
     186                 :             : {
     187                 :      341836 :     stringstream ss(path);
     188                 :      341836 :     string token;
     189                 :      341836 :     vector<string> tokens;
     190                 :             :     /* Extract each directory of the path and place into a vector.  */
     191   [ +  -  +  + ]:     2872908 :     while (getline(ss, token, '/')) {
     192                 :             :       /* Ignore any empty //, or /./ dirs.  */
     193   [ +  +  +  + ]:     2531072 :         if (token == "" || token == ".")
     194                 :      371200 :             continue;
     195                 :             :       /* When /..  is encountered, remove the most recent directory from the vector.  */
     196         [ +  + ]:     2159872 :         else if (token == "..") {
     197         [ +  - ]:      205220 :             if (!tokens.empty())
     198                 :      205220 :                 tokens.pop_back();
     199                 :             :         } else
     200         [ +  - ]:     1954652 :             tokens.push_back(token);
     201                 :             :     }
     202         [ +  - ]:      341836 :     stringstream result;
     203         [ -  + ]:      341836 :     if (tokens.empty())
     204         [ #  # ]:           0 :         return "/";
     205                 :             :     /* Reconstruct the path from the extracted directories.  */
     206         [ +  + ]:     2091268 :     for (const string &t : tokens) {
     207   [ +  -  +  - ]:     1749432 :         result << '/' << t;
     208                 :             :     }
     209         [ +  - ]:      341836 :     return result.str();
     210                 :      341836 : }
     211                 :             : 
     212                 :             : /* Global list of collected source files and their respective module.
     213                 :             :    Normally, it'll contain the sources of just one named binary, but
     214                 :             :    the '-K' option can cause multiple dwfl modules to be loaded, thus
     215                 :             :    listed.  */
     216                 :             : set<pair<string, Dwfl_Module*>> debug_sourcefiles;
     217                 :             : 
     218                 :             : static int
     219                 :          68 : collect_sourcefiles (Dwfl_Module *dwflmod,
     220                 :             :                      void **userdata __attribute__ ((unused)),
     221                 :             :                      const char *name __attribute__ ((unused)),
     222                 :             :                      Dwarf_Addr base __attribute__ ((unused)),
     223                 :             :                      void *arg __attribute__ ((unused)))
     224                 :             : {
     225                 :          68 :   Dwarf *dbg;
     226                 :          68 :   Dwarf_Addr bias; /* ignored - for addressing purposes only.  */
     227                 :             : 
     228                 :          68 :   dbg = dwfl_module_getdwarf (dwflmod, &bias);
     229                 :             : 
     230                 :          68 :   Dwarf_Off offset = 0;
     231                 :          68 :   Dwarf_Off old_offset;
     232                 :          68 :   size_t hsize;
     233                 :             :   /* Traverse all CUs of this module.  */
     234         [ +  + ]:       27520 :   while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL, NULL) == 0)
     235                 :             :     {
     236                 :       27452 :       Dwarf_Die cudie_mem;
     237                 :       27452 :       Dwarf_Die *cudie = dwarf_offdie (dbg, old_offset + hsize, &cudie_mem);
     238                 :             : 
     239         [ -  + ]:       27452 :       if (cudie == NULL)
     240                 :           0 :         continue;
     241                 :             : 
     242         [ -  + ]:       27452 :       const char *cuname = dwarf_diename (cudie) ?: "<unknown>";
     243                 :       27452 :       Dwarf_Files *files;
     244                 :       27452 :       size_t nfiles;
     245         [ -  + ]:       27452 :       if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0)
     246                 :           0 :         continue;
     247                 :             : 
     248                 :             :       /* extract DW_AT_comp_dir to resolve relative file names.  */
     249                 :       27452 :       const char *comp_dir = "";
     250                 :       27452 :       const char *const *dirs;
     251                 :       27452 :       size_t ndirs;
     252                 :             : 
     253   [ +  -  -  + ]:       27452 :       if (dwarf_getsrcdirs (files, &dirs, &ndirs) == 0 && dirs[0] != NULL)
     254                 :             :         comp_dir = dirs[0];
     255                 :           0 :       if (comp_dir == NULL)
     256                 :             :         comp_dir = "";
     257                 :             : 
     258         [ +  + ]:       27452 :       if (verbose)
     259                 :       13092 :         clog << "searching for sources for cu=" << cuname
     260                 :       13092 :                   << " comp_dir=" << comp_dir << " #files=" << nfiles
     261                 :       13092 :                   << " #dirs=" << ndirs << endl;
     262                 :             : 
     263   [ -  +  -  - ]:       27452 :       if (comp_dir[0] == '\0' && cuname[0] != '/')
     264                 :             :         {
     265                 :             :           /* This is a common symptom for dwz-compressed debug files,
     266                 :             :              where the altdebug file cannot be resolved.  */
     267         [ #  # ]:           0 :           if (verbose)
     268                 :           0 :             clog << "skipping cu=" << cuname << " due to empty comp_dir" << endl;
     269                 :           0 :           continue;
     270                 :             :         }
     271         [ +  + ]:      373480 :       for (size_t f = 1; f < nfiles; ++f)
     272                 :             :         {
     273                 :      346028 :           const char *hat;
     274         [ +  + ]:      346028 :           if (CU_only)
     275                 :             :           {
     276   [ +  -  -  + ]:       42584 :             if (strcmp(cuname, "<unknown>") == 0 || strcmp(cuname, "<artificial>") == 0 )
     277                 :        4192 :               continue;
     278                 :             :             hat = cuname;
     279                 :             :           }
     280                 :             :           else
     281                 :      303444 :             hat = dwarf_filesrc (files, f, NULL, NULL);
     282                 :             : 
     283         [ -  + ]:      303444 :           if (hat == NULL)
     284                 :           0 :             continue;
     285                 :             : 
     286         [ +  + ]:      692056 :           if (string(hat).find("<built-in>")
     287                 :      346028 :               != string::npos) /* gcc intrinsics, don't bother recording */
     288                 :        4192 :             continue;
     289                 :             : 
     290         [ +  + ]:      341836 :           string waldo;
     291         [ +  + ]:      341836 :           if (hat[0] == '/') /* absolute */
     292         [ +  - ]:       76172 :             waldo = (string (hat));
     293         [ +  - ]:      265664 :           else if (comp_dir[0] != '\0') /* comp_dir relative */
     294   [ +  -  +  -  :      265664 :             waldo = (string (comp_dir) + string ("/") + string (hat));
          +  -  +  -  +  
                      - ]
     295                 :             :           else
     296                 :             :            {
     297         [ #  # ]:           0 :              if (verbose)
     298   [ #  #  #  #  :           0 :               clog << "skipping file=" << hat << " due to empty comp_dir" << endl;
             #  #  #  # ]
     299                 :           0 :              continue;
     300                 :             :            }
     301   [ +  -  +  - ]:      341836 :           waldo = canonicalize_path (waldo);
     302   [ +  -  +  - ]:      683672 :           debug_sourcefiles.insert (make_pair(waldo, dwflmod));
     303                 :      341836 :         }
     304                 :             :     }
     305                 :          68 :   return DWARF_CB_OK;
     306                 :             : }
     307                 :             : 
     308                 :             : #ifdef HAVE_LIBARCHIVE
     309                 :          10 : void zip_files()
     310                 :             : {
     311                 :          10 :   struct archive *a = archive_write_new();
     312                 :          10 :   struct stat st;
     313                 :          10 :   char buff[BUFFER_SIZE];
     314                 :          10 :   int len;
     315                 :             :   #ifdef ENABLE_LIBDEBUGINFOD
     316                 :             :   /* Initialize a debuginfod client.  */
     317                 :          10 :   static unique_ptr <debuginfod_client, void (*)(debuginfod_client*)>
     318   [ +  -  +  -  :          10 :     client (debuginfod_begin(), &debuginfod_end);
                   +  - ]
     319                 :             :   #endif
     320                 :             : 
     321                 :          10 :   archive_write_set_format_zip(a);
     322                 :          10 :   archive_write_open_fd(a, STDOUT_FILENO);
     323                 :             : 
     324                 :          10 :   int missing_files = 0;
     325         [ +  + ]:        5400 :   for (const auto &pair : debug_sourcefiles)
     326                 :             :   {
     327                 :        5390 :     int fd = -1;
     328                 :        5390 :     const std::string &file_path = pair.first;
     329                 :        5390 :     struct archive_entry *entry = NULL;
     330         [ +  - ]:        5390 :     string entry_name;
     331                 :             : 
     332                 :             :     /* Attempt to query debuginfod client to fetch source files.  */
     333                 :             :     #ifdef ENABLE_LIBDEBUGINFOD
     334                 :        5390 :     Dwfl_Module* dwflmod = pair.second;
     335                 :             :     /* Obtain source file's build ID.  */
     336                 :        5390 :     const unsigned char *bits;
     337                 :        5390 :     GElf_Addr vaddr;
     338         [ +  - ]:        5390 :     int bits_length = dwfl_module_build_id(dwflmod, &bits, &vaddr);
     339                 :             :     /* Ensure successful client and build ID acquisition.  */
     340   [ +  -  +  - ]:        5390 :     if (client.get() != NULL && bits_length > 0)
     341                 :             :     {
     342         [ +  - ]:        5390 :       fd = debuginfod_find_source(client.get(),
     343                 :             :                                     bits, bits_length,
     344                 :             :                                     file_path.c_str(), NULL);
     345                 :             :     }
     346                 :             :     else
     347                 :             :     {
     348         [ #  # ]:           0 :         if (client.get() == NULL)
     349   [ #  #  #  # ]:           0 :             cerr << "Error: Failed to initialize debuginfod client." << endl;
     350                 :             :         else
     351   [ #  #  #  #  :           0 :             cerr << "Error: Invalid build ID length (" << bits_length << ")." << endl;
             #  #  #  # ]
     352                 :             :     }
     353                 :             : 
     354         [ +  + ]:        5390 :     if (!no_backup)
     355                 :             :     #endif /* ENABLE_LIBDEBUGINFOD */
     356                 :             :     /* Files could not be located using debuginfod, search locally */
     357         [ +  - ]:        4312 :     if (fd < 0)
     358         [ +  - ]:        4312 :       fd = open(file_path.c_str(), O_RDONLY);
     359         [ -  + ]:        5390 :     if (fd < 0)
     360                 :             :     {
     361         [ #  # ]:           0 :       if (verbose)
     362   [ #  #  #  # ]:           0 :         cerr << file_path << endl;
     363                 :           0 :       missing_files++;
     364                 :           0 :       continue;
     365                 :             :     }
     366                 :             : 
     367                 :             :     /* Create an entry for each file including file information to be placed in the zip.  */
     368         [ -  + ]:        5390 :     if (fstat(fd, &st) == -1)
     369                 :             :     {
     370         [ #  # ]:           0 :       if (verbose)
     371   [ #  #  #  # ]:           0 :         cerr << file_path << endl;
     372                 :           0 :       missing_files++;
     373         [ #  # ]:           0 :       if (verbose)
     374   [ #  #  #  #  :           0 :         cerr << "Error: Failed to get file status for " << file_path << ": " << strerror(errno) << endl;
          #  #  #  #  #  
                      # ]
     375                 :           0 :       goto next;
     376                 :             :     }
     377         [ +  - ]:        5390 :     entry = archive_entry_new();
     378                 :             :     /* Removing first "/"" to make the path "relative" before zipping, otherwise warnings are raised when unzipping.  */
     379         [ +  - ]:        5390 :     entry_name = file_path.substr(file_path.find_first_of('/') + 1);
     380         [ +  - ]:        5390 :     archive_entry_set_pathname(entry, entry_name.c_str());
     381         [ +  - ]:        5390 :     archive_entry_copy_stat(entry, &st);
     382   [ +  -  -  + ]:        5390 :     if (archive_write_header(a, entry) != ARCHIVE_OK)
     383                 :             :     {
     384         [ #  # ]:           0 :       if (verbose)
     385   [ #  #  #  # ]:           0 :         cerr << file_path << endl;
     386                 :           0 :       missing_files++;
     387         [ #  # ]:           0 :       if (verbose)
     388   [ #  #  #  #  :           0 :         cerr << "Error: failed to write header for " << file_path << ": " << archive_error_string(a) << endl;
          #  #  #  #  #  
                #  #  # ]
     389                 :           0 :       goto next;
     390                 :             :     }
     391                 :             : 
     392                 :             :     /* Write the file to the zip.  */
     393         [ +  - ]:        5390 :     len = read(fd, buff, sizeof(buff));
     394         [ -  + ]:        5390 :     if (len == -1)
     395                 :             :     {
     396         [ #  # ]:           0 :       if (verbose)
     397   [ #  #  #  # ]:           0 :         cerr << file_path << endl;
     398                 :           0 :       missing_files++;
     399         [ #  # ]:           0 :       if (verbose)
     400   [ #  #  #  #  :           0 :         cerr << "Error: Failed to open file: " << file_path << ": " << strerror(errno) <<endl;
          #  #  #  #  #  
                      # ]
     401                 :           0 :       goto next;
     402                 :             :     }
     403         [ +  + ]:       15880 :     while (len > 0)
     404                 :             :     {
     405   [ +  -  -  + ]:       10490 :       if (archive_write_data(a, buff, len) < ARCHIVE_OK)
     406                 :             :       {
     407         [ #  # ]:           0 :         if (verbose)
     408   [ #  #  #  #  :           0 :           cerr << "Error: Failed to read from the file: " << file_path << ": " << strerror(errno) << endl;
          #  #  #  #  #  
                      # ]
     409                 :             :         break;
     410                 :             :       }
     411         [ +  - ]:       10490 :       len = read(fd, buff, sizeof(buff));
     412                 :             :     }
     413                 :             : 
     414                 :        5390 : next:
     415                 :        5390 :     if (fd >= 0)
     416         [ +  - ]:        5390 :       close(fd);
     417         [ +  - ]:        5390 :     if (entry != NULL)
     418         [ +  - ]:        5390 :       archive_entry_free(entry);
     419                 :        5390 :   }
     420   [ +  +  -  + ]:          10 :   if (verbose && missing_files > 0 )
     421                 :           0 :     cerr << missing_files << " file(s) listed above could not be found.  " << endl;
     422                 :             : 
     423                 :          10 :   archive_write_close(a);
     424                 :          10 :   archive_write_free(a);
     425                 :          10 : }
     426                 :             : #endif
     427                 :             : 
     428                 :             : int
     429                 :          38 : main (int argc, char *argv[])
     430                 :             : {
     431                 :          38 :   int remaining;
     432                 :             : 
     433                 :             :   /* Parse and process arguments.  This includes opening the modules.  */
     434                 :          38 :   argp_children[0].argp = dwfl_standard_argp ();
     435                 :          38 :   argp_children[0].group = 1;
     436                 :             : 
     437                 :          38 :   Dwfl *dwfl = NULL;
     438                 :          38 :   (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
     439         [ -  + ]:          36 :   assert (dwfl != NULL);
     440                 :             :   /* Process all loaded modules - probably just one, except if -K or -p is used.  */
     441                 :          36 :   (void) dwfl_getmodules (dwfl, &collect_sourcefiles, NULL, 0);
     442                 :             : 
     443         [ +  - ]:          36 :   if (!debug_sourcefiles.empty ())
     444                 :             :   {
     445                 :             :     #ifdef HAVE_LIBARCHIVE
     446         [ +  + ]:          36 :       if (zip)
     447                 :          10 :         zip_files();
     448                 :             :       else
     449                 :             :     #endif
     450                 :             :       {
     451         [ +  + ]:       29248 :         for (const auto &pair : debug_sourcefiles)
     452                 :             :           {
     453                 :       29222 :             cout << pair.first;
     454         [ +  + ]:       29222 :             if (null_arg)
     455                 :       14072 :               cout << '\0';
     456                 :             :             else
     457                 :       15150 :               cout << '\n';
     458                 :             :           }
     459                 :             :       }
     460                 :             :   }
     461                 :             : 
     462                 :          36 :   dwfl_end (dwfl);
     463                 :          36 :   return 0;
     464                 :             : }
        

Generated by: LCOV version 2.0-1