LCOV - code coverage report
Current view: top level - c++tools - resolver.cc (source / functions) Hit Total Coverage
Test: gcc.info Lines: 111 119 93.3 %
Date: 2023-07-19 08:18:47 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /* C++ modules.  Experimental!  -*- c++ -*-
       2             :    Copyright (C) 2017-2023 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        2873 : module_resolver::module_resolver (bool map, bool xlate)
      67        2873 :   : default_map (map), default_translate (xlate)
      68             : {
      69        2873 : }
      70             : 
      71        5630 : module_resolver::~module_resolver ()
      72             : {
      73        2815 :   if (fd_repo >= 0)
      74         492 :     close (fd_repo);
      75        5630 : }
      76             : 
      77             : bool
      78        2870 : module_resolver::set_repo (std::string &&r, bool force)
      79             : {
      80        2855 :   if (force || repo.empty ())
      81             :     {
      82        2870 :       repo = std::move (r);
      83        2870 :       force = true;
      84             :     }
      85        2855 :   return force;
      86             : }
      87             : 
      88             : bool
      89          21 : module_resolver::add_mapping (std::string &&module, std::string &&file,
      90             :                               bool force)
      91             : {
      92          21 :   auto res = map.emplace (std::move (module), std::move (file));
      93          21 :   if (res.second)
      94             :     force = true;
      95           0 :   else if (force)
      96           0 :     res.first->second = std::move (file);
      97             : 
      98          21 :   return force;
      99             : }
     100             : 
     101             : int
     102          18 : module_resolver::read_tuple_file (int fd, char const *prefix, bool force)
     103             : {
     104          18 :   struct stat stat;
     105          18 :   if (fstat (fd, &stat) < 0)
     106           0 :     return -errno;
     107             : 
     108          18 :   if (!stat.st_size)
     109             :     return 0;
     110             : 
     111          18 :   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          18 :   buffer = mmap (nullptr, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
     116          18 :   if (buffer == MAP_FAILED)
     117           0 :     return -errno;
     118          18 :   struct Deleter {
     119          18 :     void operator()(void* p) const { munmap(p, size); }
     120             :     size_t size;
     121             :   };
     122          18 :   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          18 :   size_t prefix_len = prefix ? strlen (prefix) : 0;
     134          18 :   unsigned lineno = 0;
     135             : 
     136          57 :   for (char const *begin = reinterpret_cast <char const *> (buffer),
     137          18 :          *end = begin + stat.st_size, *eol;
     138          57 :        begin != end; begin = eol + 1)
     139             :     {
     140          42 :       lineno++;
     141          42 :       eol = std::find (begin, end, '\n');
     142          42 :       if (eol == end)
     143             :         // last line has no \n, ignore the line, you lose
     144             :         break;
     145             : 
     146          42 :       auto *pos = begin;
     147          42 :       bool pfx_search = prefix_len != 0;
     148             : 
     149             :     pfx_search:
     150          75 :       while (*pos == ' ' || *pos == '\t')
     151          15 :         pos++;
     152             : 
     153             :       auto *space = pos;
     154         351 :       while (*space != '\n' && *space != ' ' && *space != '\t')
     155         291 :         space++;
     156             : 
     157          60 :       if (pos == space)
     158             :         // at end of line, nothing here 
     159           3 :         continue;
     160             : 
     161          57 :       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          75 :       std::string module (pos, space);
     171         117 :       while (*space == ' ' || *space == '\t')
     172          39 :         space++;
     173          75 :       std::string file (space, eol);
     174             : 
     175          39 :       if (module[0] == '$')
     176             :         {
     177          18 :           if (module == "$root")
     178          51 :             set_repo (std::move (file));
     179             :           else
     180           3 :             return lineno;
     181             :         }
     182             :       else
     183             :         {
     184          21 :           if (file.empty ())
     185           0 :             file = GetCMIName (module);
     186          21 :           add_mapping (std::move (module), std::move (file), force);
     187             :         }
     188             :     }
     189             : 
     190             :   return 0;
     191          18 : }
     192             : 
     193             : char const *
     194       24783 : module_resolver::GetCMISuffix ()
     195             : {
     196       24783 :   return "gcm";
     197             : }
     198             : 
     199             : module_resolver *
     200        2873 : module_resolver::ConnectRequest (Cody::Server *s, unsigned version,
     201             :                                  std::string &a, std::string &i)
     202             : {
     203        2873 :   if (!version || version > Cody::Version)
     204           0 :     s->ErrorResponse ("version mismatch");
     205        2873 :   else if (a != "GCC")
     206             :     // Refuse anything but GCC
     207           0 :     ErrorResponse (s, std::string ("only GCC supported"));
     208        2873 :   else if (!ident.empty () && ident != i)
     209             :     // Failed ident check
     210           0 :     ErrorResponse (s, std::string ("bad ident"));
     211             :   else
     212             :     // Success!
     213        2873 :     s->ConnectResponse ("gcc");
     214             : 
     215        2873 :   return this;
     216             : }
     217             : 
     218             : int
     219        2873 : module_resolver::ModuleRepoRequest (Cody::Server *s)
     220             : {
     221        2873 :   s->PathnameResponse (repo);
     222        2873 :   return 0;
     223             : }
     224             : 
     225             : int
     226        3428 : module_resolver::cmi_response (Cody::Server *s, std::string &module)
     227             : {
     228        3428 :   auto iter = map.find (module);
     229        3428 :   if (iter == map.end ())
     230             :     {
     231        3410 :       std::string file = default_map ? GetCMIName (module) : std::string ();
     232        3410 :       auto res = map.emplace (module, file);
     233        3410 :       iter = res.first;
     234        3410 :     }
     235             : 
     236        3428 :   if (iter->second.empty ())
     237           3 :     s->ErrorResponse ("no such module");
     238             :   else
     239        3425 :     s->PathnameResponse (iter->second);
     240             : 
     241        3428 :   return 0;
     242             : }
     243             : 
     244             : int
     245        1726 : module_resolver::ModuleExportRequest (Cody::Server *s, Cody::Flags,
     246             :                                       std::string &module)
     247             : {
     248        1726 :   return cmi_response (s, module);
     249             : }
     250             : 
     251             : int
     252        1702 : module_resolver::ModuleImportRequest (Cody::Server *s, Cody::Flags,
     253             :                                       std::string &module)
     254             : {
     255        1702 :   return cmi_response (s, module);
     256             : }
     257             : 
     258             : int
     259       21436 : module_resolver::IncludeTranslateRequest (Cody::Server *s, Cody::Flags,
     260             :                                           std::string &include)
     261             : {
     262       21436 :   auto iter = map.find (include);
     263       21436 :   if (iter == map.end () && default_translate)
     264             :     {
     265             :       // Not found, look for it
     266       21376 :       auto file = GetCMIName (include);
     267       21376 :       struct stat statbuf;
     268       21376 :       bool ok = true;
     269             : 
     270             : #if HAVE_FSTATAT
     271       21376 :       int fd_dir = AT_FDCWD;
     272       21376 :       if (!repo.empty ())
     273             :         {
     274       21376 :           if (fd_repo == -1)
     275             :             {
     276         505 :               fd_repo = open (repo.c_str (),
     277             :                               O_RDONLY | O_CLOEXEC | O_DIRECTORY);
     278         505 :               if (fd_repo < 0)
     279           1 :                 fd_repo = -2;
     280             :             }
     281       21376 :           fd_dir = fd_repo;
     282             :         }
     283             : 
     284       21376 :       if (!repo.empty () && fd_repo < 0)
     285             :         ok = false;
     286       21362 :       else if (fstatat (fd_dir, file.c_str (), &statbuf, 0) < 0
     287       21362 :                || !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       21354 :         file.clear ();
     300       21376 :       auto res = map.emplace (include, file);
     301       21376 :       iter = res.first;
     302       21376 :     }
     303             : 
     304       21436 :   if (iter == map.end () || iter->second.empty ())
     305       21414 :     s->BoolResponse (false);
     306             :   else
     307          22 :     s->PathnameResponse (iter->second);
     308             : 
     309       21436 :   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        1651 : module_resolver::ModuleCompiledRequest (Cody::Server *s, Cody::Flags,
     318             :                                       std::string &)
     319             : {
     320        1651 :   s->OKResponse();
     321        1651 :   return 0;
     322             : }

Generated by: LCOV version 1.16