LCOV - code coverage report
Current view: top level - c++tools - resolver.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 93.3 % 119 111
Test Date: 2024-12-21 13:15:12 Functions: 100.0 % 14 14
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-2024 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                 :             : #include <memory>
      27                 :             : // C
      28                 :             : #include <cstring>
      29                 :             : // OS
      30                 :             : #include <fcntl.h>
      31                 :             : #include <unistd.h>
      32                 :             : #if 0 // 1 for testing no mmap
      33                 :             : #define MAPPED_READING 0
      34                 :             : #else
      35                 :             : #ifdef IN_GCC
      36                 :             : #if HAVE_MMAP_FILE && _POSIX_MAPPED_FILES > 0
      37                 :             : #define MAPPED_READING 1
      38                 :             : #else
      39                 :             : #define MAPPED_READING 0
      40                 :             : #endif
      41                 :             : #else
      42                 :             : #ifdef HAVE_SYS_MMAN_H
      43                 :             : #include <sys/mman.h>
      44                 :             : #define MAPPED_READING 1
      45                 :             : #else
      46                 :             : #define MAPPED_READING 0
      47                 :             : #endif
      48                 :             : #endif
      49                 :             : #endif
      50                 :             : 
      51                 :             : #include <sys/types.h>
      52                 :             : #include <sys/stat.h>
      53                 :             : 
      54                 :             : #if !defined (IN_GCC) && !MAPPED_READING
      55                 :             : #define xmalloc(X) malloc(X)
      56                 :             : #endif
      57                 :             : 
      58                 :             : #if !HOST_HAS_O_CLOEXEC
      59                 :             : #define O_CLOEXEC 0
      60                 :             : #endif
      61                 :             : 
      62                 :             : #ifndef DIR_SEPARATOR
      63                 :             : #define DIR_SEPARATOR '/'
      64                 :             : #endif
      65                 :             : 
      66                 :        3872 : module_resolver::module_resolver (bool map, bool xlate)
      67                 :        3872 :   : default_map (map), default_translate (xlate)
      68                 :             : {
      69                 :        3872 : }
      70                 :             : 
      71                 :        7460 : module_resolver::~module_resolver ()
      72                 :             : {
      73                 :        3730 :   if (fd_repo >= 0)
      74                 :        3624 :     close (fd_repo);
      75                 :        7460 : }
      76                 :             : 
      77                 :             : bool
      78                 :        3869 : module_resolver::set_repo (std::string &&r, bool force)
      79                 :             : {
      80                 :        3869 :   if (force || repo.empty ())
      81                 :             :     {
      82                 :        3869 :       repo = std::move (r);
      83                 :        3869 :       force = true;
      84                 :             :     }
      85                 :        3869 :   return force;
      86                 :             : }
      87                 :             : 
      88                 :             : bool
      89                 :          27 : module_resolver::add_mapping (std::string &&module, std::string &&file,
      90                 :             :                               bool force)
      91                 :             : {
      92                 :          27 :   auto res = map.emplace (std::move (module), std::move (file));
      93                 :          27 :   if (res.second)
      94                 :             :     force = true;
      95                 :           0 :   else if (force)
      96                 :           0 :     res.first->second = std::move (file);
      97                 :             : 
      98                 :          27 :   return force;
      99                 :             : }
     100                 :             : 
     101                 :             : int
     102                 :          24 : module_resolver::read_tuple_file (int fd, char const *prefix, bool force)
     103                 :             : {
     104                 :          24 :   struct stat stat;
     105                 :          24 :   if (fstat (fd, &stat) < 0)
     106                 :           0 :     return -errno;
     107                 :             : 
     108                 :          24 :   if (!stat.st_size)
     109                 :             :     return 0;
     110                 :             : 
     111                 :          24 :   void *buffer = nullptr;
     112                 :             : #if MAPPED_READING
     113                 :             :   // Just map the file, we're gonna read all of it, so no need for
     114                 :             :   // line buffering
     115                 :          24 :   buffer = mmap (nullptr, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
     116                 :          24 :   if (buffer == MAP_FAILED)
     117                 :           0 :     return -errno;
     118                 :          24 :   struct Deleter {
     119                 :          24 :     void operator()(void* p) const { munmap(p, size); }
     120                 :             :     size_t size;
     121                 :             :   };
     122                 :          24 :   std::unique_ptr<void, Deleter> guard(buffer, Deleter{(size_t)stat.st_size});
     123                 :             : #else
     124                 :             :   buffer = xmalloc (stat.st_size);
     125                 :             :   if (!buffer)
     126                 :             :     return -errno;
     127                 :             :   struct Deleter { void operator()(void* p) const { free(p); } };
     128                 :             :   std::unique_ptr<void, Deleter> guard(buffer);
     129                 :             :   if (read (fd, buffer, stat.st_size) != stat.st_size)
     130                 :             :     return -errno;
     131                 :             : #endif
     132                 :             : 
     133                 :          24 :   size_t prefix_len = prefix ? strlen (prefix) : 0;
     134                 :          24 :   unsigned lineno = 0;
     135                 :             : 
     136                 :          75 :   for (char const *begin = reinterpret_cast <char const *> (buffer),
     137                 :          24 :          *end = begin + stat.st_size, *eol;
     138                 :          75 :        begin != end; begin = eol + 1)
     139                 :             :     {
     140                 :          54 :       lineno++;
     141                 :          54 :       eol = std::find (begin, end, '\n');
     142                 :          54 :       if (eol == end)
     143                 :             :         // last line has no \n, ignore the line, you lose
     144                 :             :         break;
     145                 :             : 
     146                 :          54 :       auto *pos = begin;
     147                 :          54 :       bool pfx_search = prefix_len != 0;
     148                 :             : 
     149                 :             :     pfx_search:
     150                 :          87 :       while (*pos == ' ' || *pos == '\t')
     151                 :          15 :         pos++;
     152                 :             : 
     153                 :             :       auto *space = pos;
     154                 :         411 :       while (*space != '\n' && *space != ' ' && *space != '\t')
     155                 :         339 :         space++;
     156                 :             : 
     157                 :          72 :       if (pos == space)
     158                 :             :         // at end of line, nothing here 
     159                 :           3 :         continue;
     160                 :             : 
     161                 :          69 :       if (pfx_search)
     162                 :             :         {
     163                 :          18 :           if (size_t (space - pos) == prefix_len
     164                 :          18 :               && std::equal (pos, space, prefix))
     165                 :             :             pfx_search = false;
     166                 :          18 :           pos = space;
     167                 :          18 :           goto pfx_search;
     168                 :             :         }
     169                 :             : 
     170                 :          99 :       std::string module (pos, space);
     171                 :         177 :       while (*space == ' ' || *space == '\t')
     172                 :          75 :         space++;
     173                 :          99 :       std::string file (space, eol);
     174                 :             : 
     175                 :          51 :       if (module[0] == '$')
     176                 :             :         {
     177                 :          24 :           if (module == "$root")
     178                 :          21 :             set_repo (std::move (file));
     179                 :             :           else
     180                 :           3 :             return lineno;
     181                 :             :         }
     182                 :             :       else
     183                 :             :         {
     184                 :          27 :           if (file.empty ())
     185                 :           0 :             file = GetCMIName (module);
     186                 :          27 :           add_mapping (std::move (module), std::move (file), force);
     187                 :             :         }
     188                 :             :     }
     189                 :             : 
     190                 :             :   return 0;
     191                 :          24 : }
     192                 :             : 
     193                 :             : char const *
     194                 :       35601 : module_resolver::GetCMISuffix ()
     195                 :             : {
     196                 :       35601 :   return "gcm";
     197                 :             : }
     198                 :             : 
     199                 :             : module_resolver *
     200                 :        3872 : module_resolver::ConnectRequest (Cody::Server *s, unsigned version,
     201                 :             :                                  std::string &a, std::string &i)
     202                 :             : {
     203                 :        3872 :   if (!version || version > Cody::Version)
     204                 :           0 :     s->ErrorResponse ("version mismatch");
     205                 :        3872 :   else if (a != "GCC")
     206                 :             :     // Refuse anything but GCC
     207                 :           0 :     ErrorResponse (s, std::string ("only GCC supported"));
     208                 :        3872 :   else if (!ident.empty () && ident != i)
     209                 :             :     // Failed ident check
     210                 :           0 :     ErrorResponse (s, std::string ("bad ident"));
     211                 :             :   else
     212                 :             :     // Success!
     213                 :        3872 :     s->ConnectResponse ("gcc");
     214                 :             : 
     215                 :        3872 :   return this;
     216                 :             : }
     217                 :             : 
     218                 :             : int
     219                 :        3872 : module_resolver::ModuleRepoRequest (Cody::Server *s)
     220                 :             : {
     221                 :        3872 :   s->PathnameResponse (repo);
     222                 :        3872 :   return 0;
     223                 :             : }
     224                 :             : 
     225                 :             : int
     226                 :        4525 : module_resolver::cmi_response (Cody::Server *s, std::string &module)
     227                 :             : {
     228                 :        4525 :   auto iter = map.find (module);
     229                 :        4525 :   if (iter == map.end ())
     230                 :             :     {
     231                 :        4501 :       std::string file = default_map ? GetCMIName (module) : std::string ();
     232                 :        4501 :       auto res = map.emplace (module, file);
     233                 :        4501 :       iter = res.first;
     234                 :        4501 :     }
     235                 :             : 
     236                 :        4525 :   if (iter->second.empty ())
     237                 :           3 :     s->ErrorResponse ("no such module");
     238                 :             :   else
     239                 :        4522 :     s->PathnameResponse (iter->second);
     240                 :             : 
     241                 :        4525 :   return 0;
     242                 :             : }
     243                 :             : 
     244                 :             : int
     245                 :        2324 : module_resolver::ModuleExportRequest (Cody::Server *s, Cody::Flags,
     246                 :             :                                       std::string &module)
     247                 :             : {
     248                 :        2324 :   return cmi_response (s, module);
     249                 :             : }
     250                 :             : 
     251                 :             : int
     252                 :        2201 : module_resolver::ModuleImportRequest (Cody::Server *s, Cody::Flags,
     253                 :             :                                       std::string &module)
     254                 :             : {
     255                 :        2201 :   return cmi_response (s, module);
     256                 :             : }
     257                 :             : 
     258                 :             : int
     259                 :       31124 : module_resolver::IncludeTranslateRequest (Cody::Server *s, Cody::Flags,
     260                 :             :                                           std::string &include)
     261                 :             : {
     262                 :       31124 :   auto iter = map.find (include);
     263                 :       31124 :   if (iter == map.end () && default_translate)
     264                 :             :     {
     265                 :             :       // Not found, look for it
     266                 :       31103 :       auto file = GetCMIName (include);
     267                 :       31103 :       struct stat statbuf;
     268                 :       31103 :       bool ok = true;
     269                 :             : 
     270                 :             : #if HAVE_FSTATAT
     271                 :       31103 :       int fd_dir = AT_FDCWD;
     272                 :       31103 :       if (!repo.empty ())
     273                 :             :         {
     274                 :       31100 :           if (fd_repo == -1)
     275                 :             :             {
     276                 :        3833 :               fd_repo = open (repo.c_str (),
     277                 :             :                               O_RDONLY | O_CLOEXEC | O_DIRECTORY);
     278                 :        3833 :               if (fd_repo < 0)
     279                 :         142 :                 fd_repo = -2;
     280                 :             :             }
     281                 :       31100 :           fd_dir = fd_repo;
     282                 :             :         }
     283                 :             : 
     284                 :       31103 :       if (!repo.empty () && fd_repo < 0)
     285                 :             :         ok = false;
     286                 :       30344 :       else if (fstatat (fd_dir, file.c_str (), &statbuf, 0) < 0
     287                 :       30344 :                || !S_ISREG (statbuf.st_mode))
     288                 :             :         ok = false;
     289                 :             : #else
     290                 :             :       auto append = repo;
     291                 :             :       append.push_back (DIR_SEPARATOR);
     292                 :             :       append.append (file);
     293                 :             :       if (stat (append.c_str (), &statbuf) < 0
     294                 :             :           || !S_ISREG (statbuf.st_mode))
     295                 :             :         ok = false;
     296                 :             : #endif
     297                 :             :       if (!ok)
     298                 :             :         // Mark as not present
     299                 :       31065 :         file.clear ();
     300                 :       31103 :       auto res = map.emplace (include, file);
     301                 :       31103 :       iter = res.first;
     302                 :       31103 :     }
     303                 :             : 
     304                 :       31124 :   if (iter == map.end () || iter->second.empty ())
     305                 :       31086 :     s->BoolResponse (false);
     306                 :             :   else
     307                 :          38 :     s->PathnameResponse (iter->second);
     308                 :             : 
     309                 :       31124 :   return 0;
     310                 :             : }
     311                 :             : 
     312                 :             : /* This handles a client notification to the server that a CMI has been
     313                 :             :    produced for a module.  For this simplified server, we just accept
     314                 :             :    the transaction and respond with "OK".  */
     315                 :             : 
     316                 :             : int
     317                 :        2143 : module_resolver::ModuleCompiledRequest (Cody::Server *s, Cody::Flags,
     318                 :             :                                       std::string &)
     319                 :             : {
     320                 :        2143 :   s->OKResponse();
     321                 :        2143 :   return 0;
     322                 :             : }
        

Generated by: LCOV version 2.1-beta

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,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.