LCOV - code coverage report
Current view: top level - c++tools - resolver.cc (source / functions) Hit Total Coverage
Test: gcc.info Lines: 104 113 92.0 %
Date: 2021-05-08 12:53:43 Functions: 13 13 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* C++ modules.  Experimental!  -*- c++ -*-
       2                 :            :    Copyright (C) 2017-2020 Free Software Foundation, Inc.
       3                 :            :    Written by Nathan Sidwell <nathan@acm.org> while at FaceBook
       4                 :            : 
       5                 :            :    This file is part of GCC.
       6                 :            : 
       7                 :            :    GCC is free software; you can redistribute it and/or modify it
       8                 :            :    under the terms of the GNU General Public License as published by
       9                 :            :    the Free Software Foundation; either version 3, or (at your option)
      10                 :            :    any later version.
      11                 :            : 
      12                 :            :    GCC is distributed in the hope that it will be useful, but
      13                 :            :    WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15                 :            :    General Public License for more details.
      16                 :            : 
      17                 :            : You should have received a copy of the GNU General Public License
      18                 :            : along with GCC; see the file COPYING3.  If not see
      19                 :            : <http://www.gnu.org/licenses/>.  */
      20                 :            : 
      21                 :            : #include "config.h"
      22                 :            : 
      23                 :            : #include "resolver.h"
      24                 :            : // C++
      25                 :            : #include <algorithm>
      26                 :            : // C
      27                 :            : #include <cstring>
      28                 :            : // OS
      29                 :            : #include <fcntl.h>
      30                 :            : #include <unistd.h>
      31                 :            : #if 0 // 1 for testing no mmap
      32                 :            : #define MAPPED_READING 0
      33                 :            : #else
      34                 :            : #ifdef IN_GCC
      35                 :            : #if HAVE_MMAP_FILE && _POSIX_MAPPED_FILES > 0
      36                 :            : #define MAPPED_READING 1
      37                 :            : #else
      38                 :            : #define MAPPED_READING 0
      39                 :            : #endif
      40                 :            : #else
      41                 :            : #ifdef HAVE_SYS_MMAN_H
      42                 :            : #include <sys/mman.h>
      43                 :            : #define MAPPED_READING 1
      44                 :            : #else
      45                 :            : #define MAPPED_READING 0
      46                 :            : #endif
      47                 :            : #endif
      48                 :            : #endif
      49                 :            : 
      50                 :            : #include <sys/types.h>
      51                 :            : #include <sys/stat.h>
      52                 :            : 
      53                 :            : #if !defined (IN_GCC) && !MAPPED_READING
      54                 :            : #define xmalloc(X) malloc(X)
      55                 :            : #endif
      56                 :            : 
      57                 :            : #if !HOST_HAS_O_CLOEXEC
      58                 :            : #define O_CLOEXEC 0
      59                 :            : #endif
      60                 :            : 
      61                 :            : #ifndef DIR_SEPARATOR
      62                 :            : #define DIR_SEPARATOR '/'
      63                 :            : #endif
      64                 :            : 
      65                 :       2670 : module_resolver::module_resolver (bool map, bool xlate)
      66                 :       2670 :   : default_map (map), default_translate (xlate)
      67                 :            : {
      68                 :       2670 : }
      69                 :            : 
      70                 :       5224 : module_resolver::~module_resolver ()
      71                 :            : {
      72                 :       2612 :   if (fd_repo >= 0)
      73                 :        440 :     close (fd_repo);
      74                 :       5224 : }
      75                 :            : 
      76                 :            : bool
      77                 :       2667 : module_resolver::set_repo (std::string &&r, bool force)
      78                 :            : {
      79                 :       2667 :   if (force || repo.empty ())
      80                 :            :     {
      81                 :       2667 :       repo = std::move (r);
      82                 :       2667 :       force = true;
      83                 :            :     }
      84                 :       2667 :   return force;
      85                 :            : }
      86                 :            : 
      87                 :            : bool
      88                 :         21 : module_resolver::add_mapping (std::string &&module, std::string &&file,
      89                 :            :                               bool force)
      90                 :            : {
      91                 :         21 :   auto res = map.emplace (std::move (module), std::move (file));
      92                 :         21 :   if (res.second)
      93                 :            :     force = true;
      94                 :          0 :   else if (force)
      95                 :          0 :     res.first->second = std::move (file);
      96                 :            : 
      97                 :         21 :   return force;
      98                 :            : }
      99                 :            : 
     100                 :            : int
     101                 :         18 : module_resolver::read_tuple_file (int fd, char const *prefix, bool force)
     102                 :            : {
     103                 :         18 :   struct stat stat;
     104                 :         18 :   if (fstat (fd, &stat) < 0)
     105                 :          0 :     return -errno;
     106                 :            : 
     107                 :         18 :   if (!stat.st_size)
     108                 :            :     return 0;
     109                 :            : 
     110                 :         18 :   void *buffer = nullptr;
     111                 :            : #if MAPPED_READING
     112                 :            :   // Just map the file, we're gonna read all of it, so no need for
     113                 :            :   // line buffering
     114                 :         18 :   buffer = mmap (nullptr, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
     115                 :         18 :   if (buffer == MAP_FAILED)
     116                 :          0 :     return -errno;
     117                 :            : #else
     118                 :            :   buffer = xmalloc (stat.st_size);
     119                 :            :   if (!buffer)
     120                 :            :     return -errno;
     121                 :            :   if (read (fd, buffer, stat.st_size) != stat.st_size)
     122                 :            :     return -errno;
     123                 :            : #endif
     124                 :            : 
     125                 :         18 :   size_t prefix_len = prefix ? strlen (prefix) : 0;
     126                 :         18 :   unsigned lineno = 0;
     127                 :            : 
     128                 :         57 :   for (char const *begin = reinterpret_cast <char const *> (buffer),
     129                 :         18 :          *end = begin + stat.st_size, *eol;
     130                 :         57 :        begin != end; begin = eol + 1)
     131                 :            :     {
     132                 :         42 :       lineno++;
     133                 :         42 :       eol = std::find (begin, end, '\n');
     134                 :         42 :       if (eol == end)
     135                 :            :         // last line has no \n, ignore the line, you lose
     136                 :            :         break;
     137                 :            : 
     138                 :         42 :       auto *pos = begin;
     139                 :         42 :       bool pfx_search = prefix_len != 0;
     140                 :            : 
     141                 :         75 :     pfx_search:
     142                 :         75 :       while (*pos == ' ' || *pos == '\t')
     143                 :         15 :         pos++;
     144                 :            : 
     145                 :            :       auto *space = pos;
     146                 :        351 :       while (*space != '\n' && *space != ' ' && *space != '\t')
     147                 :        291 :         space++;
     148                 :            : 
     149                 :         60 :       if (pos == space)
     150                 :            :         // at end of line, nothing here 
     151                 :          3 :         continue;
     152                 :            : 
     153                 :         57 :       if (pfx_search)
     154                 :            :         {
     155                 :         18 :           if (size_t (space - pos) == prefix_len
     156                 :         18 :               && std::equal (pos, space, prefix))
     157                 :            :             pfx_search = false;
     158                 :         18 :           pos = space;
     159                 :         18 :           goto pfx_search;
     160                 :            :         }
     161                 :            : 
     162                 :         75 :       std::string module (pos, space);
     163                 :         78 :       while (*space == ' ' || *space == '\t')
     164                 :         39 :         space++;
     165                 :         75 :       std::string file (space, eol);
     166                 :            : 
     167                 :         39 :       if (module[0] == '$')
     168                 :            :         {
     169                 :         18 :           if (module == "$root")
     170                 :         15 :             set_repo (std::move (file));
     171                 :            :           else
     172                 :          3 :             return lineno;
     173                 :            :         }
     174                 :            :       else
     175                 :            :         {
     176                 :         21 :           if (file.empty ())
     177                 :          0 :             file = GetCMIName (module);
     178                 :         21 :           add_mapping (std::move (module), std::move (file), force);
     179                 :            :         }
     180                 :            :     }
     181                 :            : 
     182                 :            : #if MAPPED_READING
     183                 :         15 :   munmap (buffer, stat.st_size);
     184                 :            : #else
     185                 :            :   free (buffer);
     186                 :            : #endif
     187                 :            : 
     188                 :         15 :   return 0;
     189                 :            : }
     190                 :            : 
     191                 :            : char const *
     192                 :      22284 : module_resolver::GetCMISuffix ()
     193                 :            : {
     194                 :      22284 :   return "gcm";
     195                 :            : }
     196                 :            : 
     197                 :            : module_resolver *
     198                 :       2670 : module_resolver::ConnectRequest (Cody::Server *s, unsigned version,
     199                 :            :                                  std::string &a, std::string &i)
     200                 :            : {
     201                 :       2670 :   if (!version || version > Cody::Version)
     202                 :          0 :     s->ErrorResponse ("version mismatch");
     203                 :       2670 :   else if (a != "GCC")
     204                 :            :     // Refuse anything but GCC
     205                 :          0 :     ErrorResponse (s, std::string ("only GCC supported"));
     206                 :       2670 :   else if (!ident.empty () && ident != i)
     207                 :            :     // Failed ident check
     208                 :          0 :     ErrorResponse (s, std::string ("bad ident"));
     209                 :            :   else
     210                 :            :     // Success!
     211                 :       2670 :     s->ConnectResponse ("gcc");
     212                 :            : 
     213                 :       2670 :   return this;
     214                 :            : }
     215                 :            : 
     216                 :            : int
     217                 :       2670 : module_resolver::ModuleRepoRequest (Cody::Server *s)
     218                 :            : {
     219                 :       2670 :   s->PathnameResponse (repo);
     220                 :       2670 :   return 0;
     221                 :            : }
     222                 :            : 
     223                 :            : int
     224                 :       3183 : module_resolver::cmi_response (Cody::Server *s, std::string &module)
     225                 :            : {
     226                 :       3183 :   auto iter = map.find (module);
     227                 :       3183 :   if (iter == map.end ())
     228                 :            :     {
     229                 :       6330 :       std::string file = default_map ? GetCMIName (module) : std::string ();
     230                 :       3165 :       auto res = map.emplace (module, file);
     231                 :       3165 :       iter = res.first;
     232                 :            :     }
     233                 :            : 
     234                 :       3183 :   if (iter->second.empty ())
     235                 :          3 :     s->ErrorResponse ("no such module");
     236                 :            :   else
     237                 :       3180 :     s->PathnameResponse (iter->second);
     238                 :            : 
     239                 :       3183 :   return 0;
     240                 :            : }
     241                 :            : 
     242                 :            : int
     243                 :       1591 : module_resolver::ModuleExportRequest (Cody::Server *s, Cody::Flags,
     244                 :            :                                       std::string &module)
     245                 :            : {
     246                 :       1591 :   return cmi_response (s, module);
     247                 :            : }
     248                 :            : 
     249                 :            : int
     250                 :       1592 : module_resolver::ModuleImportRequest (Cody::Server *s, Cody::Flags,
     251                 :            :                                       std::string &module)
     252                 :            : {
     253                 :       1592 :   return cmi_response (s, module);
     254                 :            : }
     255                 :            : 
     256                 :            : int
     257                 :      19122 : module_resolver::IncludeTranslateRequest (Cody::Server *s, Cody::Flags,
     258                 :            :                                           std::string &include)
     259                 :            : {
     260                 :      19122 :   auto iter = map.find (include);
     261                 :      19122 :   if (iter == map.end () && default_translate)
     262                 :            :     {
     263                 :            :       // Not found, look for it
     264                 :      38244 :       auto file = GetCMIName (include);
     265                 :      19122 :       struct stat statbuf;
     266                 :      19122 :       bool ok = true;
     267                 :            : 
     268                 :            : #if HAVE_FSTATAT
     269                 :      19122 :       int fd_dir = AT_FDCWD;
     270                 :      19122 :       if (!repo.empty ())
     271                 :            :         {
     272                 :      19122 :           if (fd_repo == -1)
     273                 :            :             {
     274                 :        452 :               fd_repo = open (repo.c_str (),
     275                 :            :                               O_RDONLY | O_CLOEXEC | O_DIRECTORY);
     276                 :        452 :               if (fd_repo < 0)
     277                 :          0 :                 fd_repo = -2;
     278                 :            :             }
     279                 :      19122 :           fd_dir = fd_repo;
     280                 :            :         }
     281                 :            : 
     282                 :      19122 :       if (!repo.empty () && fd_repo < 0)
     283                 :            :         ok = false;
     284                 :      19122 :       else if (fstatat (fd_dir, file.c_str (), &statbuf, 0) < 0
     285                 :      19122 :                || !S_ISREG (statbuf.st_mode))
     286                 :            :         ok = false;
     287                 :            : #else
     288                 :            :       auto append = repo;
     289                 :            :       append.push_back (DIR_SEPARATOR);
     290                 :            :       append.append (file);
     291                 :            :       if (stat (append.c_str (), &statbuf) < 0
     292                 :            :           || !S_ISREG (statbuf.st_mode))
     293                 :            :         ok = false;
     294                 :            : #endif
     295                 :            :       if (!ok)
     296                 :            :         // Mark as not present
     297                 :      19097 :         file.clear ();
     298                 :      19122 :       auto res = map.emplace (include, file);
     299                 :      19122 :       iter = res.first;
     300                 :            :     }
     301                 :            : 
     302                 :      19122 :   if (iter == map.end () || iter->second.empty ())
     303                 :      19097 :     s->BoolResponse (false);
     304                 :            :   else
     305                 :         25 :     s->PathnameResponse (iter->second);
     306                 :            : 
     307                 :      19122 :   return 0;
     308                 :            : }
     309                 :            : 

Generated by: LCOV version 1.15+git.20200812.d100e6c

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto --enable-host-shared. GCC test suite is run with the built compiler.