LCOV - code coverage report
Current view: top level - gcc/go/gofrontend - import-archive.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 46.7 % 334 156
Test Date: 2024-04-20 14:03:02 Functions: 84.2 % 19 16
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // import-archive.cc -- Go frontend read import data from an archive file.
       2                 :             : 
       3                 :             : // Copyright 2009 The Go Authors. All rights reserved.
       4                 :             : // Use of this source code is governed by a BSD-style
       5                 :             : // license that can be found in the LICENSE file.
       6                 :             : 
       7                 :             : #include "go-system.h"
       8                 :             : 
       9                 :             : #include "go-diagnostics.h"
      10                 :             : #include "import.h"
      11                 :             : 
      12                 :             : #ifndef O_BINARY
      13                 :             : #define O_BINARY 0
      14                 :             : #endif
      15                 :             : 
      16                 :             : // Archive magic numbers.
      17                 :             : 
      18                 :             : static const char armag[] =
      19                 :             : {
      20                 :             :   '!', '<', 'a', 'r', 'c', 'h', '>', '\n'
      21                 :             : };
      22                 :             : 
      23                 :             : static const char armagt[] =
      24                 :             : {
      25                 :             :   '!', '<', 't', 'h', 'i', 'n', '>', '\n'
      26                 :             : };
      27                 :             : 
      28                 :             : static const char armagb[] =
      29                 :             : {
      30                 :             :   '<', 'b', 'i', 'g', 'a', 'f', '>', '\n'
      31                 :             : };
      32                 :             : 
      33                 :             : static const char arfmag[2] = { '`', '\n' };
      34                 :             : 
      35                 :             : // Archive fixed length header for AIX big format.
      36                 :             : 
      37                 :             : struct Archive_fl_header
      38                 :             : {
      39                 :             :   // Archive magic string.
      40                 :             :   char fl_magic[8];
      41                 :             :   // Offset to member table.
      42                 :             :   char fl_memoff[20];
      43                 :             :   // Offset to global symbol table.
      44                 :             :   char fl_gstoff[20];
      45                 :             :   // Offset to global symbol table for 64-bit objects.
      46                 :             :   char fl_gst64off[20];
      47                 :             :   // Offset to first archive member.
      48                 :             :   char fl_fstmoff[20];
      49                 :             :   // Offset to last archive member.
      50                 :             :   char fl_lstmoff[20];
      51                 :             :   // Offset to first member on free list.
      52                 :             :   char fl_freeoff[20];
      53                 :             : };
      54                 :             : 
      55                 :             : // The header of an entry in an archive.  This is all readable text,
      56                 :             : // padded with spaces where necesary.
      57                 :             : 
      58                 :             : struct Archive_header
      59                 :             : {
      60                 :             :   // The entry name.
      61                 :             :   char ar_name[16];
      62                 :             :   // The file modification time.
      63                 :             :   char ar_date[12];
      64                 :             :   // The user's UID in decimal.
      65                 :             :   char ar_uid[6];
      66                 :             :   // The user's GID in decimal.
      67                 :             :   char ar_gid[6];
      68                 :             :   // The file mode in octal.
      69                 :             :   char ar_mode[8];
      70                 :             :   // The file size in decimal.
      71                 :             :   char ar_size[10];
      72                 :             :   // The final magic code.
      73                 :             :   char ar_fmag[2];
      74                 :             : };
      75                 :             : 
      76                 :             : // The header of an entry in an AIX big archive.
      77                 :             : // This is followed by ar_namlen bytes + 2 bytes for arfmag.
      78                 :             : 
      79                 :             : struct Archive_big_header
      80                 :             : {
      81                 :             :   // The file size in decimal.
      82                 :             :   char ar_size[20];
      83                 :             :   // The next member offset in decimal.
      84                 :             :   char ar_nxtmem[20];
      85                 :             :   // The previous member offset in decimal.
      86                 :             :   char ar_prvmem[20];
      87                 :             :   // The file modification time in decimal.
      88                 :             :   char ar_date[12];
      89                 :             :   // The user's UID in decimal.
      90                 :             :   char ar_uid[12];
      91                 :             :   // The user's GID in decimal.
      92                 :             :   char ar_gid[12];
      93                 :             :   // The file mode in octal.
      94                 :             :   char ar_mode[12];
      95                 :             :   // The file name length in decimal.
      96                 :             :   char ar_namlen[4];
      97                 :             : };
      98                 :             : 
      99                 :             : // The functions in this file extract Go export data from an archive.
     100                 :             : 
     101                 :             : const int Import::archive_magic_len;
     102                 :             : 
     103                 :             : // Return true if BYTES, which are from the start of the file, are an
     104                 :             : // archive magic number.
     105                 :             : 
     106                 :             : bool
     107                 :         702 : Import::is_archive_magic(const char* bytes)
     108                 :             : {
     109                 :         702 :   return (memcmp(bytes, armag, Import::archive_magic_len) == 0
     110                 :           0 :           || memcmp(bytes, armagt, Import::archive_magic_len) == 0
     111                 :         702 :           || memcmp(bytes, armagb, Import::archive_magic_len) == 0);
     112                 :             : }
     113                 :             : 
     114                 :             : // An object used to read an archive file.
     115                 :             : 
     116                 :             : class Archive_file
     117                 :             : {
     118                 :             :  public:
     119                 :         702 :   Archive_file(const std::string& filename, int fd, Location location)
     120                 :         702 :     : filename_(filename), fd_(fd), filesize_(-1), first_member_offset_(0),
     121                 :         702 :       extended_names_(), is_thin_archive_(false), is_big_archive_(false),
     122                 :         702 :       location_(location), nested_archives_()
     123                 :         702 :   { }
     124                 :             : 
     125                 :             :   // Initialize.
     126                 :             :   bool
     127                 :             :   initialize();
     128                 :             : 
     129                 :             :   // Return the file name.
     130                 :             :   const std::string&
     131                 :             :   filename() const
     132                 :             :   { return this->filename_; }
     133                 :             : 
     134                 :             :   // Get the file size.
     135                 :             :   off_t
     136                 :        5154 :   filesize() const
     137                 :        5154 :   { return this->filesize_; }
     138                 :             : 
     139                 :             :   // Return the offset of the first member.
     140                 :             :   off_t
     141                 :         702 :   first_member_offset() const
     142                 :         702 :   { return this->first_member_offset_; }
     143                 :             : 
     144                 :             :   // Return whether this is a thin archive.
     145                 :             :   bool
     146                 :             :   is_thin_archive() const
     147                 :             :   { return this->is_thin_archive_; }
     148                 :             : 
     149                 :             :   // Return whether this is a big archive.
     150                 :             :   bool
     151                 :             :   is_big_archive() const
     152                 :             :   { return this->is_big_archive_; }
     153                 :             : 
     154                 :             :   // Return the location of the import statement.
     155                 :             :   Location
     156                 :             :   location() const
     157                 :             :   { return this->location_; }
     158                 :             : 
     159                 :             :   // Read bytes.
     160                 :             :   bool
     161                 :             :   read(off_t offset, off_t size, char*);
     162                 :             : 
     163                 :             :   // Parse a decimal in readable text.
     164                 :             :   bool
     165                 :             :   parse_decimal(const char* str, off_t size, long* res) const;
     166                 :             : 
     167                 :             :   // Read the archive header at OFF, setting *PNAME, *SIZE,
     168                 :             :   // *NESTED_OFF and *NEXT_OFF.
     169                 :             :   bool
     170                 :             :   read_header(off_t off, std::string* pname, off_t* size, off_t* nested_off,
     171                 :             :               off_t* next_off);
     172                 :             : 
     173                 :             :   // Interpret the header of HDR, the header of the archive member at
     174                 :             :   // file offset OFF.  Return whether it succeeded.  Set *SIZE to the
     175                 :             :   // size of the member.  Set *PNAME to the name of the member.  Set
     176                 :             :   // *NESTED_OFF to the offset in a nested archive.
     177                 :             :   bool
     178                 :             :   interpret_header(const Archive_header* hdr, off_t off,
     179                 :             :                    std::string* pname, off_t* size, off_t* nested_off) const;
     180                 :             : 
     181                 :             :   // Get the file and offset for an archive member.
     182                 :             :   bool
     183                 :             :   get_file_and_offset(off_t off, const std::string& hdrname,
     184                 :             :                       off_t nested_off, int* memfd, off_t* memoff,
     185                 :             :                       std::string* memname);
     186                 :             : 
     187                 :             :  private:
     188                 :             :   // Initialize a big archive (AIX)
     189                 :             :   bool
     190                 :             :   initialize_big_archive();
     191                 :             : 
     192                 :             :   // Initialize a normal archive
     193                 :             :   bool
     194                 :             :   initialize_archive();
     195                 :             : 
     196                 :             :   // Read the big archive header at OFF, setting *PNAME, *SIZE and *NEXT_OFF.
     197                 :             :   bool
     198                 :             :   read_big_archive_header(off_t off, std::string* pname,
     199                 :             :                           off_t* size, off_t* next_off);
     200                 :             : 
     201                 :             :   // Read the normal archive header at OFF, setting *PNAME, *SIZE,
     202                 :             :   // *NESTED_OFF and *NEXT_OFF.
     203                 :             :   bool
     204                 :             :   read_archive_header(off_t off, std::string* pname, off_t* size,
     205                 :             :                       off_t* nested_off, off_t* next_off);
     206                 :             : 
     207                 :             :   // For keeping track of open nested archives in a thin archive file.
     208                 :             :   typedef std::map<std::string, Archive_file*> Nested_archive_table;
     209                 :             : 
     210                 :             :   // The name of the file.
     211                 :             :   std::string filename_;
     212                 :             :   // The file descriptor.
     213                 :             :   int fd_;
     214                 :             :   // The file size;
     215                 :             :   off_t filesize_;
     216                 :             :   // The first member offset;
     217                 :             :   off_t first_member_offset_;
     218                 :             :   // The extended name table.
     219                 :             :   std::string extended_names_;
     220                 :             :   // Whether this is a thin archive.
     221                 :             :   bool is_thin_archive_;
     222                 :             :   // Whether this is a big archive.
     223                 :             :   bool is_big_archive_;
     224                 :             :   // The location of the import statements.
     225                 :             :   Location location_;
     226                 :             :   // Table of nested archives.
     227                 :             :   Nested_archive_table nested_archives_;
     228                 :             : };
     229                 :             : 
     230                 :             : bool
     231                 :         702 : Archive_file::initialize()
     232                 :             : {
     233                 :         702 :   struct stat st;
     234                 :         702 :   if (fstat(this->fd_, &st) < 0)
     235                 :             :     {
     236                 :           0 :       go_error_at(this->location_, "%s: %m", this->filename_.c_str());
     237                 :           0 :       return false;
     238                 :             :     }
     239                 :         702 :   this->filesize_ = st.st_size;
     240                 :             : 
     241                 :         702 :   char buf[sizeof(armagt)];
     242                 :         702 :   if (::lseek(this->fd_, 0, SEEK_SET) < 0
     243                 :         702 :       || ::read(this->fd_, buf, sizeof(armagt)) != sizeof(armagt))
     244                 :             :     {
     245                 :           0 :       go_error_at(this->location_, "%s: %m", this->filename_.c_str());
     246                 :           0 :       return false;
     247                 :             :     }
     248                 :         702 :   if (memcmp(buf, armagt, sizeof(armagt)) == 0)
     249                 :           0 :     this->is_thin_archive_ = true;
     250                 :         702 :   else if (memcmp(buf, armagb, sizeof(armagb)) == 0)
     251                 :           0 :     this->is_big_archive_ = true;
     252                 :             : 
     253                 :         702 :   if (this->is_big_archive_)
     254                 :           0 :     return this->initialize_big_archive();
     255                 :             :   else
     256                 :         702 :     return this->initialize_archive();
     257                 :             : }
     258                 :             : 
     259                 :             : // Initialize a big archive (AIX).
     260                 :             : 
     261                 :             : bool
     262                 :           0 : Archive_file::initialize_big_archive()
     263                 :             : {
     264                 :           0 :   Archive_fl_header flhdr;
     265                 :             : 
     266                 :             :   // Read the fixed length header.
     267                 :           0 :   if (::lseek(this->fd_, 0, SEEK_SET) < 0
     268                 :           0 :       || ::read(this->fd_, &flhdr, sizeof(flhdr)) != sizeof(flhdr))
     269                 :             :     {
     270                 :           0 :       go_error_at(this->location_, "%s: could not read archive header",
     271                 :             :                   this->filename_.c_str());
     272                 :           0 :       return false;
     273                 :             :     }
     274                 :             : 
     275                 :             :   // Parse offset of the first member.
     276                 :           0 :   long off;
     277                 :           0 :   if (!this->parse_decimal(flhdr.fl_fstmoff, sizeof(flhdr.fl_fstmoff), &off))
     278                 :             :     {
     279                 :           0 :       char* buf = new char[sizeof(flhdr.fl_fstmoff) + 1];
     280                 :           0 :       memcpy(buf, flhdr.fl_fstmoff, sizeof(flhdr.fl_fstmoff));
     281                 :           0 :       go_error_at(this->location_,
     282                 :             :                   ("%s: malformed first member offset in archive header"
     283                 :             :                    " (expected decimal, got %s)"),
     284                 :             :                   this->filename_.c_str(), buf);
     285                 :           0 :       delete[] buf;
     286                 :           0 :       return false;
     287                 :             :     }
     288                 :           0 :   if (off == 0) // Empty archive.
     289                 :           0 :     this->first_member_offset_ = this->filesize_;
     290                 :             :   else
     291                 :           0 :     this->first_member_offset_ = off;
     292                 :             :   return true;
     293                 :             : }
     294                 :             : 
     295                 :             : // Initialize a normal archive.
     296                 :             : 
     297                 :             : bool
     298                 :         702 : Archive_file::initialize_archive()
     299                 :             : {
     300                 :         702 :   this->first_member_offset_ = sizeof(armag);
     301                 :         702 :   if (this->first_member_offset_ == this->filesize_)
     302                 :             :     {
     303                 :             :       // Empty archive.
     304                 :             :       return true;
     305                 :             :     }
     306                 :             : 
     307                 :             :   // Look for the extended name table.
     308                 :         702 :   std::string filename;
     309                 :         702 :   off_t size;
     310                 :         702 :   off_t next_off;
     311                 :         702 :   if (!this->read_header(this->first_member_offset_, &filename,
     312                 :             :                          &size, NULL, &next_off))
     313                 :             :     return false;
     314                 :         702 :   if (filename.empty())
     315                 :             :     {
     316                 :             :       // We found the symbol table.
     317                 :         702 :       if (!this->read_header(next_off, &filename, &size, NULL, NULL))
     318                 :           0 :         filename.clear();
     319                 :             :     }
     320                 :         702 :   if (filename == "/")
     321                 :             :     {
     322                 :           0 :       char* rdbuf = new char[size];
     323                 :           0 :       if (::read(this->fd_, rdbuf, size) != size)
     324                 :             :         {
     325                 :           0 :           go_error_at(this->location_, "%s: could not read extended names",
     326                 :             :                    filename.c_str());
     327                 :           0 :           delete[] rdbuf;
     328                 :           0 :           return false;
     329                 :             :         }
     330                 :           0 :       this->extended_names_.assign(rdbuf, size);
     331                 :           0 :       delete[] rdbuf;
     332                 :             :     }
     333                 :             : 
     334                 :             :   return true;
     335                 :         702 : }
     336                 :             : 
     337                 :             : // Read bytes from the file.
     338                 :             : 
     339                 :             : bool
     340                 :           0 : Archive_file::read(off_t offset, off_t size, char* buf)
     341                 :             : {
     342                 :           0 :   if (::lseek(this->fd_, offset, SEEK_SET) < 0
     343                 :           0 :       || ::read(this->fd_, buf, size) != size)
     344                 :             :     {
     345                 :           0 :       go_error_at(this->location_, "%s: %m", this->filename_.c_str());
     346                 :           0 :       return false;
     347                 :             :     }
     348                 :             :   return true;
     349                 :             : }
     350                 :             : 
     351                 :             : // Parse a decimal in readable text.
     352                 :             : 
     353                 :             : bool
     354                 :        3630 : Archive_file::parse_decimal(const char* str, off_t size, long* res) const
     355                 :             : {
     356                 :        3630 :   char* buf = new char[size + 1];
     357                 :        3630 :   memcpy(buf, str, size);
     358                 :        3630 :   char* ps = buf + size;
     359                 :       23819 :   while (ps > buf && ps[-1] == ' ')
     360                 :       20189 :     --ps;
     361                 :        3630 :   *ps = '\0';
     362                 :             : 
     363                 :        3630 :   errno = 0;
     364                 :        3630 :   char* end;
     365                 :        3630 :   *res = strtol(buf, &end, 10);
     366                 :        3630 :   if (*end != '\0'
     367                 :        3630 :       || *res < 0
     368                 :        3630 :       || (*res == LONG_MAX && errno == ERANGE))
     369                 :             :     {
     370                 :           0 :       delete[] buf;
     371                 :           0 :       return false;
     372                 :             :     }
     373                 :        3630 :   delete[] buf;
     374                 :        3630 :   return true;
     375                 :             : }
     376                 :             : 
     377                 :             : // Read the header at OFF.  Set *PNAME to the name, *SIZE to the size,
     378                 :             : // *NESTED_OFF to the nested offset, and *NEXT_OFF to the next member offset.
     379                 :             : 
     380                 :             : bool
     381                 :        3630 : Archive_file::read_header(off_t off, std::string* pname, off_t* size,
     382                 :             :                           off_t* nested_off, off_t* next_off)
     383                 :             : {
     384                 :        3630 :   if (::lseek(this->fd_, off, SEEK_SET) < 0)
     385                 :             :     {
     386                 :           0 :       go_error_at(this->location_, "%s: %m", this->filename_.c_str());
     387                 :           0 :       return false;
     388                 :             :     }
     389                 :        3630 :   if (this->is_big_archive_)
     390                 :           0 :     return this->read_big_archive_header(off, pname, size, next_off);
     391                 :             :   else
     392                 :        3630 :     return this->read_archive_header(off, pname, size, nested_off, next_off);
     393                 :             : }
     394                 :             : 
     395                 :             : // Read the big archive header at OFF, setting *PNAME, *SIZE and *NEXT_OFF.
     396                 :             : 
     397                 :             : bool
     398                 :           0 : Archive_file::read_big_archive_header(off_t off, std::string* pname,
     399                 :             :                                       off_t* size, off_t* next_off)
     400                 :             : {
     401                 :           0 :   Archive_big_header hdr;
     402                 :           0 :   ssize_t got;
     403                 :             : 
     404                 :           0 :   got = ::read(this->fd_, &hdr, sizeof hdr);
     405                 :           0 :   if (got != sizeof hdr)
     406                 :             :     {
     407                 :           0 :       if (got < 0)
     408                 :           0 :         go_error_at(this->location_, "%s: %m", this->filename_.c_str());
     409                 :           0 :       else if (got > 0)
     410                 :           0 :         go_error_at(this->location_, "%s: short entry header at %ld",
     411                 :             :                     this->filename_.c_str(), static_cast<long>(off));
     412                 :             :       else
     413                 :           0 :         go_error_at(this->location_, "%s: unexpected EOF at %ld",
     414                 :             :                     this->filename_.c_str(), static_cast<long>(off));
     415                 :             :     }
     416                 :             : 
     417                 :           0 :   long local_size;
     418                 :           0 :   if (!this->parse_decimal(hdr.ar_size, sizeof(hdr.ar_size), &local_size))
     419                 :             :     {
     420                 :           0 :       char* buf = new char[sizeof(hdr.ar_size) + 1];
     421                 :           0 :       memcpy(buf, hdr.ar_size, sizeof(hdr.ar_size));
     422                 :           0 :       go_error_at(this->location_,
     423                 :             :                   ("%s: malformed size in entry header at %ld"
     424                 :             :                    " (expected decimal, got %s)"),
     425                 :             :                   this->filename_.c_str(), static_cast<long>(off), buf);
     426                 :           0 :       delete[] buf;
     427                 :           0 :       return false;
     428                 :             :     }
     429                 :           0 :   *size = local_size;
     430                 :             : 
     431                 :           0 :   long namlen;
     432                 :           0 :   if (!this->parse_decimal(hdr.ar_namlen, sizeof(hdr.ar_namlen), &namlen))
     433                 :             :     {
     434                 :           0 :       char* buf = new char[sizeof(hdr.ar_namlen) + 1];
     435                 :           0 :       memcpy(buf, hdr.ar_namlen, sizeof(hdr.ar_namlen));
     436                 :           0 :       go_error_at(this->location_,
     437                 :             :                   ("%s: malformed name length in entry header at %ld"
     438                 :             :                    " (expected decimal, got %s)"),
     439                 :             :                   this->filename_.c_str(), static_cast<long>(off), buf);
     440                 :           0 :       delete[] buf;
     441                 :           0 :       return false;
     442                 :             :     }
     443                 :             :   // Read member name following member header.
     444                 :           0 :   char* rdbuf = new char[namlen];
     445                 :           0 :   got = ::read(this->fd_, rdbuf, namlen);
     446                 :           0 :   if (got != namlen)
     447                 :             :     {
     448                 :           0 :       go_error_at(this->location_,
     449                 :             :                   "%s: malformed member name in entry header at %ld",
     450                 :             :                   this->filename_.c_str(), static_cast<long>(off));
     451                 :           0 :       delete[] rdbuf;
     452                 :           0 :       return false;
     453                 :             :     }
     454                 :           0 :   pname->assign(rdbuf, namlen);
     455                 :           0 :   delete[] rdbuf;
     456                 :             : 
     457                 :           0 :   long local_next_off;
     458                 :           0 :   if (!this->parse_decimal(hdr.ar_nxtmem, sizeof(hdr.ar_nxtmem), &local_next_off))
     459                 :             :     {
     460                 :           0 :       char* buf = new char[sizeof(hdr.ar_nxtmem) + 1];
     461                 :           0 :       memcpy(buf, hdr.ar_nxtmem, sizeof(hdr.ar_nxtmem));
     462                 :           0 :       go_error_at(this->location_,
     463                 :             :                   ("%s: malformed next member offset in entry header at %ld"
     464                 :             :                    " (expected decimal, got %s)"),
     465                 :             :                   this->filename_.c_str(), static_cast<long>(off), buf);
     466                 :           0 :       delete[] buf;
     467                 :           0 :       return false;
     468                 :             :     }
     469                 :           0 :   if (next_off != NULL)
     470                 :             :     {
     471                 :           0 :       if (local_next_off == 0) // Last member.
     472                 :           0 :         *next_off = this->filesize_;
     473                 :             :       else
     474                 :           0 :         *next_off = local_next_off;
     475                 :             :     }
     476                 :             :   return true;
     477                 :             : }
     478                 :             : 
     479                 :             : // Read the normal archive header at OFF, setting *PNAME, *SIZE,
     480                 :             : // *NESTED_OFF and *NEXT_OFF.
     481                 :             : 
     482                 :             : bool
     483                 :        3630 : Archive_file::read_archive_header(off_t off, std::string* pname, off_t* size,
     484                 :             :                                   off_t* nested_off, off_t* next_off)
     485                 :             : {
     486                 :        3630 :   Archive_header hdr;
     487                 :        3630 :   ssize_t got = ::read(this->fd_, &hdr, sizeof hdr);
     488                 :        3630 :   if (got != sizeof hdr)
     489                 :             :     {
     490                 :           0 :       if (got < 0)
     491                 :           0 :         go_error_at(this->location_, "%s: %m", this->filename_.c_str());
     492                 :           0 :       else if (got > 0)
     493                 :           0 :         go_error_at(this->location_, "%s: short archive header at %ld",
     494                 :             :                     this->filename_.c_str(), static_cast<long>(off));
     495                 :             :       else
     496                 :           0 :         go_error_at(this->location_, "%s: unexpected EOF at %ld",
     497                 :             :                     this->filename_.c_str(), static_cast<long>(off));
     498                 :             :     }
     499                 :        3630 :   off_t local_nested_off;
     500                 :        3630 :   if (!this->interpret_header(&hdr, off, pname, size, &local_nested_off))
     501                 :             :     return false;
     502                 :        3630 :   if (nested_off != NULL)
     503                 :        2226 :     *nested_off = local_nested_off;
     504                 :             : 
     505                 :        3630 :   off_t local_next_off;
     506                 :        3630 :   local_next_off = off + sizeof(Archive_header);
     507                 :        3630 :   if (!this->is_thin_archive_ || pname->empty() || *pname == "/")
     508                 :        3630 :     local_next_off += *size;
     509                 :        3630 :   if ((local_next_off & 1) != 0)
     510                 :          19 :     ++local_next_off;
     511                 :        3630 :   if (local_next_off > this->filesize_) // Last member.
     512                 :             :     local_next_off = this->filesize_;
     513                 :        3630 :   if (next_off != NULL)
     514                 :        2928 :     *next_off = local_next_off;
     515                 :             :   return true;
     516                 :             : }
     517                 :             : 
     518                 :             : // Interpret the header of HDR, the header of the archive member at
     519                 :             : // file offset OFF.
     520                 :             : 
     521                 :             : bool
     522                 :        3630 : Archive_file::interpret_header(const Archive_header* hdr, off_t off,
     523                 :             :                                std::string* pname, off_t* size,
     524                 :             :                                off_t* nested_off) const
     525                 :             : {
     526                 :        3630 :   if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
     527                 :             :     {
     528                 :           0 :       go_error_at(this->location_, "%s: malformed archive header at %lu",
     529                 :             :                   this->filename_.c_str(), static_cast<unsigned long>(off));
     530                 :           0 :       return false;
     531                 :             :     }
     532                 :             : 
     533                 :        3630 :   long local_size;
     534                 :        3630 :   if (!this->parse_decimal(hdr->ar_size, sizeof hdr->ar_size, &local_size))
     535                 :             :     {
     536                 :           0 :       go_error_at(this->location_, "%s: malformed archive header size at %lu",
     537                 :             :                   this->filename_.c_str(), static_cast<unsigned long>(off));
     538                 :           0 :       return false;
     539                 :             :     }
     540                 :        3630 :   *size = local_size;
     541                 :             : 
     542                 :        3630 :   *nested_off = 0;
     543                 :        3630 :   if (hdr->ar_name[0] != '/')
     544                 :             :     {
     545                 :        2226 :       const char* name_end = strchr(hdr->ar_name, '/');
     546                 :        2226 :       if (name_end == NULL
     547                 :        2226 :           || name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name))
     548                 :             :         {
     549                 :           0 :           go_error_at(this->location_,
     550                 :             :                       "%s: malformed archive header name at %lu",
     551                 :             :                       this->filename_.c_str(), static_cast<unsigned long>(off));
     552                 :           0 :           return false;
     553                 :             :         }
     554                 :        2226 :       pname->assign(hdr->ar_name, name_end - hdr->ar_name);
     555                 :             :     }
     556                 :        1404 :   else if (hdr->ar_name[1] == ' ')
     557                 :             :     {
     558                 :             :       // This is the symbol table.
     559                 :        1404 :       pname->clear();
     560                 :             :     }
     561                 :           0 :   else if (hdr->ar_name[1] == 'S' && hdr->ar_name[2] == 'Y'
     562                 :           0 :            && hdr->ar_name[3] == 'M' && hdr->ar_name[4] == '6'
     563                 :           0 :            && hdr->ar_name[5] == '4' && hdr->ar_name[6] == '/'
     564                 :           0 :            && hdr->ar_name[7] == ' '
     565                 :             :           )
     566                 :             :     {
     567                 :             :       // 64-bit symbol table.
     568                 :           0 :       pname->clear();
     569                 :             :     }
     570                 :           0 :   else if (hdr->ar_name[1] == '/')
     571                 :             :     {
     572                 :             :       // This is the extended name table.
     573                 :           0 :       pname->assign(1, '/');
     574                 :             :     }
     575                 :             :   else
     576                 :             :     {
     577                 :           0 :       char* end;
     578                 :           0 :       errno = 0;
     579                 :           0 :       long x = strtol(hdr->ar_name + 1, &end, 10);
     580                 :           0 :       long y = 0;
     581                 :           0 :       if (*end == ':')
     582                 :           0 :         y = strtol(end + 1, &end, 10);
     583                 :           0 :       if (*end != ' '
     584                 :           0 :           || x < 0
     585                 :           0 :           || (x == LONG_MAX && errno == ERANGE)
     586                 :           0 :           || static_cast<size_t>(x) >= this->extended_names_.size())
     587                 :             :         {
     588                 :           0 :           go_error_at(this->location_, "%s: bad extended name index at %lu",
     589                 :             :                       this->filename_.c_str(), static_cast<unsigned long>(off));
     590                 :           0 :           return false;
     591                 :             :         }
     592                 :             : 
     593                 :           0 :       const char* name = this->extended_names_.data() + x;
     594                 :           0 :       const char* name_end = strchr(name, '\n');
     595                 :           0 :       if (static_cast<size_t>(name_end - name) > this->extended_names_.size()
     596                 :           0 :           || name_end[-1] != '/')
     597                 :             :         {
     598                 :           0 :           go_error_at(this->location_,
     599                 :             :                       "%s: bad extended name entry at header %lu",
     600                 :             :                       this->filename_.c_str(), static_cast<unsigned long>(off));
     601                 :           0 :           return false;
     602                 :             :         }
     603                 :           0 :       pname->assign(name, name_end - 1 - name);
     604                 :           0 :       *nested_off = y;
     605                 :             :     }
     606                 :             : 
     607                 :             :   return true;
     608                 :             : }
     609                 :             : 
     610                 :             : // Get the file and offset for an archive member.
     611                 :             : 
     612                 :             : bool
     613                 :        1524 : Archive_file::get_file_and_offset(off_t off, const std::string& hdrname,
     614                 :             :                                   off_t nested_off, int* memfd, off_t* memoff,
     615                 :             :                                   std::string* memname)
     616                 :             : {
     617                 :        1524 :   if (this->is_big_archive_)
     618                 :             :     {
     619                 :           0 :       *memfd = this->fd_;
     620                 :           0 :       *memoff = (off + sizeof(Archive_big_header) + hdrname.length()
     621                 :           0 :                  + sizeof(arfmag));
     622                 :           0 :       if ((*memoff & 1) != 0)
     623                 :           0 :         ++*memoff;
     624                 :           0 :       *memname = this->filename_ + '(' + hdrname + ')';
     625                 :           0 :       return true;
     626                 :             :     }
     627                 :        1524 :   else if (!this->is_thin_archive_)
     628                 :             :     {
     629                 :        1524 :       *memfd = this->fd_;
     630                 :        1524 :       *memoff = off + sizeof(Archive_header);
     631                 :        1524 :       *memname = this->filename_ + '(' + hdrname + ')';
     632                 :        1524 :       return true;
     633                 :             :     }
     634                 :             : 
     635                 :           0 :   std::string filename = hdrname;
     636                 :           0 :   if (!IS_ABSOLUTE_PATH(filename.c_str()))
     637                 :             :     {
     638                 :           0 :       const char* archive_path = this->filename_.c_str();
     639                 :           0 :       const char* basename = lbasename(archive_path);
     640                 :           0 :       if (basename > archive_path)
     641                 :           0 :         filename.replace(0, 0,
     642                 :           0 :                          this->filename_.substr(0, basename - archive_path));
     643                 :             :     }
     644                 :             : 
     645                 :           0 :   if (nested_off > 0)
     646                 :             :     {
     647                 :             :       // This is a member of a nested archive.
     648                 :           0 :       Archive_file* nfile;
     649                 :           0 :       Nested_archive_table::const_iterator p =
     650                 :           0 :         this->nested_archives_.find(filename);
     651                 :           0 :       if (p != this->nested_archives_.end())
     652                 :           0 :         nfile = p->second;
     653                 :             :       else
     654                 :             :         {
     655                 :           0 :           int nfd = open(filename.c_str(), O_RDONLY | O_BINARY);
     656                 :           0 :           if (nfd < 0)
     657                 :             :             {
     658                 :           0 :               go_error_at(this->location_, "%s: cannot open nested archive %s",
     659                 :             :                           this->filename_.c_str(), filename.c_str());
     660                 :           0 :               return false;
     661                 :             :             }
     662                 :           0 :           nfile = new Archive_file(filename, nfd, this->location_);
     663                 :           0 :           if (!nfile->initialize())
     664                 :             :             {
     665                 :           0 :               delete nfile;
     666                 :           0 :               return false;
     667                 :             :             }
     668                 :           0 :           this->nested_archives_[filename] = nfile;
     669                 :             :         }
     670                 :             : 
     671                 :           0 :       std::string nname;
     672                 :           0 :       off_t nsize;
     673                 :           0 :       off_t nnested_off;
     674                 :           0 :       if (!nfile->read_header(nested_off, &nname, &nsize, &nnested_off, NULL))
     675                 :             :         return false;
     676                 :           0 :       return nfile->get_file_and_offset(nested_off, nname, nnested_off,
     677                 :           0 :                                         memfd, memoff, memname);
     678                 :           0 :     }
     679                 :             : 
     680                 :             :   // An external member of a thin archive.
     681                 :           0 :   *memfd = open(filename.c_str(), O_RDONLY | O_BINARY);
     682                 :           0 :   if (*memfd < 0)
     683                 :             :     {
     684                 :           0 :       go_error_at(this->location_, "%s: %m", filename.c_str());
     685                 :           0 :       return false;
     686                 :             :     }
     687                 :           0 :   *memoff = 0;
     688                 :           0 :   *memname = filename;
     689                 :           0 :   return true;
     690                 :           0 : }
     691                 :             : 
     692                 :             : // An archive member iterator.  This is more-or-less copied from gold.
     693                 :             : 
     694                 :        5856 : class Archive_iterator
     695                 :             : {
     696                 :             :  public:
     697                 :             :   // The header of an archive member.  This is what this iterator
     698                 :             :   // points to.
     699                 :        1404 :   struct Header
     700                 :             :   {
     701                 :             :     // The name of the member.
     702                 :             :     std::string name;
     703                 :             :     // The file offset of the member.
     704                 :             :     off_t off;
     705                 :             :     // The file offset of a nested archive member.
     706                 :             :     off_t nested_off;
     707                 :             :     // The size of the member.
     708                 :             :     off_t size;
     709                 :             :   };
     710                 :             : 
     711                 :        1404 :   Archive_iterator(Archive_file* afile, off_t off)
     712                 :        1404 :     : afile_(afile), off_(off)
     713                 :        1404 :   { this->read_next_header(); }
     714                 :             : 
     715                 :             :   const Header&
     716                 :             :   operator*() const
     717                 :             :   { return this->header_; }
     718                 :             : 
     719                 :             :   const Header*
     720                 :             :   operator->() const
     721                 :             :   { return &this->header_; }
     722                 :             : 
     723                 :             :   Archive_iterator&
     724                 :        1524 :   operator++()
     725                 :             :   {
     726                 :        1524 :     if (this->off_ == this->afile_->filesize())
     727                 :             :       return *this;
     728                 :        1524 :     this->off_ = this->next_off_;
     729                 :        1524 :     this->read_next_header();
     730                 :        1524 :     return *this;
     731                 :             :   }
     732                 :             : 
     733                 :             :   Archive_iterator
     734                 :        1524 :   operator++(int)
     735                 :             :   {
     736                 :        1524 :     Archive_iterator ret = *this;
     737                 :        1524 :     ++*this;
     738                 :        1524 :     return ret;
     739                 :             :   }
     740                 :             : 
     741                 :             :   bool
     742                 :             :   operator==(const Archive_iterator& p) const
     743                 :             :   { return this->off_ == p->off; }
     744                 :             : 
     745                 :             :   bool
     746                 :        2226 :   operator!=(const Archive_iterator& p) const
     747                 :        2226 :   { return this->off_ != p->off; }
     748                 :             : 
     749                 :             :  private:
     750                 :             :   void
     751                 :             :   read_next_header();
     752                 :             : 
     753                 :             :   // The underlying archive file.
     754                 :             :   Archive_file* afile_;
     755                 :             :   // The current offset in the file.
     756                 :             :   off_t off_;
     757                 :             :   // The offset of the next member.
     758                 :             :   off_t next_off_;
     759                 :             :   // The current archive header.
     760                 :             :   Header header_;
     761                 :             : };
     762                 :             : 
     763                 :             : // Read the next archive header.
     764                 :             : 
     765                 :             : void
     766                 :        2928 : Archive_iterator::read_next_header()
     767                 :             : {
     768                 :        2928 :   off_t filesize = this->afile_->filesize();
     769                 :        4332 :   while (true)
     770                 :             :     {
     771                 :        3630 :       if (this->off_ == filesize)
     772                 :             :         {
     773                 :        1404 :           this->header_.off = filesize;
     774                 :        1404 :           return;
     775                 :             :         }
     776                 :             : 
     777                 :        2226 :       if (!this->afile_->read_header(this->off_, &this->header_.name,
     778                 :             :                                      &this->header_.size,
     779                 :             :                                      &this->header_.nested_off,
     780                 :             :                                      &this->next_off_))
     781                 :             :         {
     782                 :           0 :           this->header_.off = filesize;
     783                 :           0 :           this->off_ = filesize;
     784                 :           0 :           return;
     785                 :             :         }
     786                 :        2226 :       this->header_.off = this->off_;
     787                 :             : 
     788                 :             :       // Skip special members.
     789                 :        2226 :       if (!this->header_.name.empty() && this->header_.name != "/")
     790                 :             :         return;
     791                 :             : 
     792                 :         702 :       this->off_ = this->next_off_;
     793                 :             :     }
     794                 :             : }
     795                 :             : 
     796                 :             : // Initial iterator.
     797                 :             : 
     798                 :             : Archive_iterator
     799                 :         702 : archive_begin(Archive_file* afile)
     800                 :             : {
     801                 :         702 :   return Archive_iterator(afile, afile->first_member_offset());
     802                 :             : }
     803                 :             : 
     804                 :             : // Final iterator.
     805                 :             : 
     806                 :             : Archive_iterator
     807                 :         702 : archive_end(Archive_file* afile)
     808                 :             : {
     809                 :         702 :   return Archive_iterator(afile, afile->filesize());
     810                 :             : }
     811                 :             : 
     812                 :             : // A type of Import_stream which concatenates other Import_streams
     813                 :             : // together.
     814                 :             : 
     815                 :             : class Stream_concatenate : public Import::Stream
     816                 :             : {
     817                 :             :  public:
     818                 :         702 :   Stream_concatenate()
     819                 :         702 :     : inputs_()
     820                 :             :   { }
     821                 :             : 
     822                 :             :   // Add a new stream.
     823                 :             :   void
     824                 :         702 :   add(Import::Stream* is)
     825                 :        1404 :   { this->inputs_.push_back(is); }
     826                 :             : 
     827                 :             :  protected:
     828                 :             :   bool
     829                 :             :   do_peek(size_t, const char**);
     830                 :             : 
     831                 :             :   void
     832                 :             :   do_advance(size_t);
     833                 :             : 
     834                 :             :  private:
     835                 :             :   std::list<Import::Stream*> inputs_;
     836                 :             : };
     837                 :             : 
     838                 :             : // Peek ahead.
     839                 :             : 
     840                 :             : bool
     841                 :     9783558 : Stream_concatenate::do_peek(size_t length, const char** bytes)
     842                 :             : {
     843                 :         702 :   while (true)
     844                 :             :     {
     845                 :     9784260 :       if (this->inputs_.empty())
     846                 :             :         return false;
     847                 :     9783558 :       if (this->inputs_.front()->peek(length, bytes))
     848                 :             :         return true;
     849                 :         702 :       delete this->inputs_.front();
     850                 :         702 :       this->inputs_.pop_front();
     851                 :             :     }
     852                 :             : }
     853                 :             : 
     854                 :             : // Advance.
     855                 :             : 
     856                 :             : void
     857                 :     6603699 : Stream_concatenate::do_advance(size_t skip)
     858                 :             : {
     859                 :           0 :   while (true)
     860                 :             :     {
     861                 :     6603699 :       if (this->inputs_.empty())
     862                 :             :         return;
     863                 :     6603699 :       if (!this->inputs_.front()->at_eof())
     864                 :             :         {
     865                 :             :           // We just assume that this will do the right thing.  It
     866                 :             :           // should be OK since we should never want to skip past
     867                 :             :           // multiple streams.
     868                 :     6603699 :           this->inputs_.front()->advance(skip);
     869                 :     6603699 :           return;
     870                 :             :         }
     871                 :           0 :       delete this->inputs_.front();
     872                 :           0 :       this->inputs_.pop_front();
     873                 :             :     }
     874                 :             : }
     875                 :             : 
     876                 :             : // Import data from an archive.  We walk through the archive and
     877                 :             : // import data from each member.
     878                 :             : 
     879                 :             : Import::Stream*
     880                 :         702 : Import::find_archive_export_data(const std::string& filename, int fd,
     881                 :             :                                  Location location)
     882                 :             : {
     883                 :         702 :   Archive_file afile(filename, fd, location);
     884                 :         702 :   if (!afile.initialize())
     885                 :             :     return NULL;
     886                 :             : 
     887                 :         702 :   Stream_concatenate* ret = new Stream_concatenate;
     888                 :             : 
     889                 :         702 :   bool any_data = false;
     890                 :         702 :   bool any_members = false;
     891                 :         702 :   Archive_iterator pend = archive_end(&afile);
     892                 :        2226 :   for (Archive_iterator p = archive_begin(&afile); p != pend; p++)
     893                 :             :     {
     894                 :        1524 :       any_members = true;
     895                 :        1524 :       int member_fd;
     896                 :        1524 :       off_t member_off;
     897                 :        1524 :       std::string member_name;
     898                 :        1524 :       if (!afile.get_file_and_offset(p->off, p->name, p->nested_off,
     899                 :             :                                      &member_fd, &member_off, &member_name))
     900                 :           0 :         return NULL;
     901                 :             : 
     902                 :        1524 :       Import::Stream* is = Import::find_object_export_data(member_name,
     903                 :             :                                                            member_fd,
     904                 :             :                                                            member_off,
     905                 :             :                                                            location);
     906                 :        1524 :       if (is != NULL)
     907                 :             :         {
     908                 :         702 :           ret->add(is);
     909                 :         702 :           any_data = true;
     910                 :             :         }
     911                 :        1524 :     }
     912                 :             : 
     913                 :         702 :   if (!any_members)
     914                 :             :     {
     915                 :             :       // It's normal to have an empty archive file when using gobuild.
     916                 :           0 :       return new Stream_from_string("");
     917                 :             :     }
     918                 :             : 
     919                 :         702 :   if (!any_data)
     920                 :             :     {
     921                 :           0 :       delete ret;
     922                 :           0 :       return NULL;
     923                 :             :     }
     924                 :             : 
     925                 :             :   return ret;
     926                 :         702 : }
        

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.