source: rtems-tools/rtemstoolkit/rld-files.cpp @ 3618a62

Last change on this file since 3618a62 was 82c8788, checked in by Chris Johns <chrisj@…>, on Apr 14, 2018 at 4:15:07 AM

rtemstoolkit/rtl-file: Remove a file on close if requested

Close #3395

  • Property mode set to 100644
File size: 38.9 KB
Line 
1/*
2 * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <algorithm>
22
23#include <errno.h>
24#include <fcntl.h>
25#include <stdio.h>
26#include <string.h>
27#include <sys/stat.h>
28#include <unistd.h>
29
30#include <rld.h>
31
32#if __WIN32__
33#define CREATE_MODE (S_IRUSR | S_IWUSR)
34#define OPEN_FLAGS  (O_BINARY)
35#else
36#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
37#define OPEN_FLAGS  (0)
38#endif
39
40namespace rld
41{
42  namespace files
43  {
44    /**
45     * Scan the decimal number returning the value found.
46     */
47    uint64_t
48    scan_decimal (const uint8_t* string, size_t len)
49    {
50      uint64_t value = 0;
51
52      while (len && (*string != ' '))
53      {
54        value *= 10;
55        value += *string - '0';
56        ++string;
57        --len;
58      }
59
60      return value;
61    }
62
63    void
64    set_number (uint32_t value, uint8_t* string, size_t len, bool octal = false)
65    {
66      std::ostringstream oss;
67      if (octal)
68        oss << std::oct;
69      oss << value;
70      size_t l = oss.str ().length ();
71      if (l > len)
72        l = len;
73      memcpy (string, oss.str ().c_str (), l);
74    }
75
76    file::file (const std::string& aname,
77                const std::string& oname,
78                off_t              offset,
79                size_t             size)
80      : aname_ (aname),
81        oname_ (oname),
82        offset_ (offset),
83        size_ (size)
84    {
85    }
86
87    file::file (const std::string& path, bool is_object)
88      : offset_ (0),
89        size_ (0)
90    {
91      set (path, is_object);
92    }
93
94    file::file ()
95      : offset_ (0),
96        size_ (0)
97    {
98    }
99
100    void
101    file::set (const std::string& path, bool is_object)
102    {
103      /*
104       * If there is a path look for a colon. If there is no colon we assume
105       * it is an object file. If the colon is the last character in the path
106       * it is just an archive.
107       */
108      if (!path.empty ())
109      {
110        bool get_size = false;
111        if (is_object)
112        {
113          size_t colon = path.find_last_of (':');
114          if ((colon != std::string::npos) && (colon > RLD_DRIVE_SEPARATOR))
115          {
116            aname_ = path.substr (0, colon - 1);
117            oname_ = path.substr (colon + 1);
118            // @todo Add offset scanning.
119          }
120          else
121          {
122            oname_ = path;
123            get_size = true;
124          }
125        }
126        else
127        {
128          aname_ = path;
129            get_size = true;
130        }
131
132        if (get_size)
133        {
134          struct stat sb;
135          if (::stat (path.c_str (), &sb) == 0)
136            size_ = sb.st_size;
137        }
138      }
139    }
140
141    bool
142    file::is_archive () const
143    {
144      return !aname_.empty () && oname_.empty ();
145    }
146
147    bool
148    file::is_object () const
149    {
150      return !oname_.empty ();
151    }
152
153    bool
154    file::is_valid () const
155    {
156      return !aname_.empty () || !oname_.empty ();
157    }
158
159    bool
160    file::exists () const
161    {
162      /*
163       * No name set returns false.
164       */
165      bool result = false;
166      const std::string p = path ();
167      if (!p.empty ())
168        result = path::check_file (p);
169      return result;
170    }
171
172    const std::string
173    file::path () const
174    {
175      if (!aname_.empty ())
176        return aname_;
177      return oname_;
178    }
179
180    const std::string
181    file::full () const
182    {
183      std::string f;
184      if (!aname_.empty ())
185      {
186        f = aname_;
187        if (!oname_.empty ())
188          f += ':';
189      }
190      if (!oname_.empty ())
191        f += oname_;
192      if (!aname_.empty () && !oname_.empty ())
193        f += '@' + rld::to_string (offset_);
194      return f;
195    }
196
197    const std::string
198    file::basename () const
199    {
200      return rld::path::basename (full ());
201    }
202
203    const std::string&
204    file::aname () const
205    {
206      return aname_;
207    }
208
209    const std::string&
210    file::oname () const
211    {
212      return oname_;
213    }
214
215    off_t
216    file::offset () const
217    {
218       return offset_;
219    }
220
221    size_t
222    file::size () const
223    {
224       return size_;
225    }
226
227    image::image (file& name)
228      : name_ (name),
229        references_ (0),
230        fd_ (-1),
231        symbol_refs (0),
232        writable (false),
233        remove (false)
234    {
235    }
236
237    image::image (const std::string& path, bool is_object)
238      : name_ (path, is_object),
239        references_ (0),
240        fd_ (-1),
241        symbol_refs (0),
242        writable (false),
243        remove (false)
244    {
245    }
246
247    image::image ()
248      : references_ (0),
249        fd_ (-1),
250        symbol_refs (0),
251        writable (false),
252        remove (false)
253    {
254    }
255
256    image::~image ()
257    {
258      if (references_)
259        std::cerr << "rtl:file:image: references when destructing";
260      if (fd_ >= 0)
261      {
262        ::close (fd_);
263        if (writable && remove)
264        {
265          if (rld::verbose () >= RLD_VERBOSE_INFO)
266            std::cout << "image::close: removing " << name ().full ()
267                        << std::endl;
268          ::unlink (name_.path ().c_str ());
269        }
270      }
271    }
272
273    void
274    image::open (file& name)
275    {
276      name_ = name;
277      open ();
278    }
279
280    void
281    image::open (bool writable_)
282    {
283      const std::string path = name_.path ();
284
285      if (path.empty ())
286        throw rld::error ("No file name", "open:" + path);
287
288      if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
289        std::cout << "image::open:  " << name (). full ()
290                  << " refs:" << references_ + 1
291                  << " writable:" << (char*) (writable_ ? "yes" : "no")
292                  << std::endl;
293
294      if (fd_ < 0)
295      {
296        writable = writable_;
297
298        if (writable)
299          fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDWR | O_CREAT | O_TRUNC, CREATE_MODE);
300        else
301          fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDONLY);
302        if (fd_ < 0)
303          throw rld::error (::strerror (errno), "open:" + path);
304      }
305      else
306      {
307        if (writable_ != writable)
308          throw rld::error ("Cannot change write status", "open:" + path);
309      }
310
311      ++references_;
312    }
313
314    void
315    image::close ()
316    {
317      if (references_ > 0)
318      {
319        if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
320          std::cout << "image::close: " << name ().full ()
321                    << " refs:" << references_ << std::endl;
322
323        --references_;
324        if (references_ == 0)
325        {
326          ::close (fd_);
327          fd_ = -1;
328          if (writable && remove)
329          {
330            if (rld::verbose () >= RLD_VERBOSE_INFO)
331              std::cout << "image::close: removing " << name ().full ()
332                        << std::endl;
333            ::unlink (name_.path ().c_str ());
334            remove = false;
335          }
336        }
337      }
338    }
339
340    ssize_t
341    image::read (void* buffer_, size_t size)
342    {
343      uint8_t* buffer = static_cast <uint8_t*> (buffer_);
344      size_t   have_read = 0;
345      size_t   to_read = size;
346      while (have_read < size)
347      {
348        const ssize_t rsize = ::read (fd (), buffer, to_read);
349        if (rsize < 0)
350          throw rld::error (strerror (errno), "read:" + name ().path ());
351        if (rsize == 0)
352          break;
353        have_read += rsize;
354        to_read -= rsize;
355        buffer += rsize;
356      }
357      return have_read;
358    }
359
360    ssize_t
361    image::write (const void* buffer_, size_t size)
362    {
363      const uint8_t* buffer = static_cast <const uint8_t*> (buffer_);
364      size_t         have_written = 0;
365      size_t         to_write = size;
366      while (have_written < size)
367      {
368        const ssize_t wsize = ::write (fd (), buffer, to_write);
369        if (wsize < 0)
370          throw rld::error (strerror (errno), "write:" + name ().path ());
371        have_written += wsize;
372        to_write -= wsize;
373        buffer += wsize;
374      }
375      return have_written;
376    }
377
378    void
379    image::seek (off_t offset)
380    {
381      if (::lseek (fd (), name_.offset () + offset, SEEK_SET) < 0)
382        throw rld::error (strerror (errno), "lseek:" + name ().path ());
383    }
384
385    bool
386    image::seek_read (off_t offset, uint8_t* buffer, size_t size)
387    {
388      seek (offset);
389      return size == (size_t) read (buffer, size);
390    }
391
392    bool
393    image::seek_write (off_t offset, const void* buffer, size_t size)
394    {
395      seek (offset);
396      return size == (size_t) write (buffer, size);
397    }
398
399    const file&
400    image::name () const
401    {
402      return name_;
403    }
404
405    int
406    image::references () const
407    {
408      return references_;
409    }
410
411    size_t
412    image::size () const
413    {
414      return name ().size ();
415    }
416
417    int
418    image::fd () const
419    {
420      return fd_;
421    }
422
423    rld::elf::file&
424    image::elf ()
425    {
426      return elf_;
427    }
428
429    byteorder
430    image::get_byteorder () const
431    {
432      switch (elf_.data_type ())
433      {
434        case ELFDATA2LSB:
435          return little_endian;
436        case ELFDATA2MSB:
437          return big_endian;
438      }
439      throw rld::error ("invalid elf data type", "byteorder: " + name ().path ());
440    }
441
442    void
443    image::symbol_referenced ()
444    {
445      ++symbol_refs;
446    }
447
448    int
449    image::symbol_references () const
450    {
451      return symbol_refs;
452    }
453
454    void
455    copy_file (image& in, image& out, size_t size)
456    {
457      #define COPY_FILE_BUFFER_SIZE (8 * 1024)
458      uint8_t* buffer = 0;
459
460      if (size == 0)
461        size = in.name ().size ();
462
463      try
464      {
465        buffer = new uint8_t[COPY_FILE_BUFFER_SIZE];
466        while (size)
467        {
468          /*
469           * @fixme the reading and writing are not POSIX; sigints could split them.
470           */
471
472          size_t l = size < COPY_FILE_BUFFER_SIZE ? size : COPY_FILE_BUFFER_SIZE;
473          ssize_t r = ::read (in.fd (), buffer, l);
474
475          if (r < 0)
476            throw rld::error (::strerror (errno), "reading: " + in.name ().full ());
477
478          if (r == 0)
479          {
480            std::ostringstream oss;
481            oss << "reading: " + in.name ().full () << " (" << size << ')';
482            throw rld::error ("input too short", oss.str ());
483          }
484
485          ssize_t w = ::write (out.fd (), buffer, r);
486
487          if (w < 0)
488            throw rld::error (::strerror (errno), "writing: " + out.name ().full ());
489
490          if (w != r)
491            throw rld::error ("output trucated", "writing: " + out.name ().full ());
492
493          size -= r;
494        }
495      }
496      catch (...)
497      {
498        delete [] buffer;
499        throw;
500      }
501
502      if (buffer)
503        delete [] buffer;
504    }
505
506    /**
507     * Defines for the header of an archive.
508     */
509    #define rld_archive_ident         "!<arch>\n"
510    #define rld_archive_ident_size    (sizeof (rld_archive_ident) - 1)
511    #define rld_archive_fhdr_base     rld_archive_ident_size
512    #define rld_archive_fname         (0)
513    #define rld_archive_fname_size    (16)
514    #define rld_archive_mtime         (16)
515    #define rld_archive_mtime_size    (12)
516    #define rld_archive_uid           (28)
517    #define rld_archive_uid_size      (6)
518    #define rld_archive_gid           (34)
519    #define rld_archive_gid_size      (6)
520    #define rld_archive_mode          (40)
521    #define rld_archive_mode_size     (8)
522    #define rld_archive_size          (48)
523    #define rld_archive_size_size     (10)
524    #define rld_archive_magic         (58)
525    #define rld_archive_magic_size    (2)
526    #define rld_archive_fhdr_size     (60)
527    #define rld_archive_max_file_size (1024)
528
529    archive::archive (const std::string& path)
530      : image (path, false)
531    {
532      if (!name ().is_valid ())
533        throw rld_error_at ("name is empty");
534      if (!name ().is_archive ())
535        throw rld_error_at ("name is not an archive: " + name ().oname ());
536    }
537
538    archive::~archive ()
539    {
540      end ();
541      close ();
542    }
543
544    void
545    archive::begin ()
546    {
547      if (references () == 1)
548      {
549        elf ().begin (name ().full (), fd ());
550
551        /*
552         * Make sure it is an archive.
553         */
554        if (!elf ().is_archive ())
555          throw rld::error ("Not an archive.",
556                            "archive-begin:" + name ().full ());
557      }
558    }
559
560    void
561    archive::end ()
562    {
563      if (references () == 1)
564        elf ().end ();
565    }
566
567    bool
568    archive::is (const std::string& path) const
569    {
570      return name ().path () == path;
571    }
572
573    bool
574    archive::is_valid ()
575    {
576      open ();
577      uint8_t header[rld_archive_ident_size];
578      seek_read (0, &header[0], rld_archive_ident_size);
579      bool result = ::memcmp (header, rld_archive_ident,
580                              rld_archive_ident_size) == 0 ? true : false;
581      close ();
582      return result;
583    }
584
585    void
586    archive::load_objects (objects& objs)
587    {
588      off_t extended_file_names = 0;
589      off_t offset = rld_archive_fhdr_base;
590      size_t size = 0;
591
592      while (true)
593      {
594        uint8_t header[rld_archive_fhdr_size];
595
596        if (!read_header (offset, &header[0]))
597          break;
598
599        /*
600         * The archive file headers are always aligned to an even address.
601         */
602        size =
603          (scan_decimal (&header[rld_archive_size],
604                         rld_archive_size_size) + 1) & ~1;
605
606        /*
607         * Check for the GNU extensions.
608         */
609        if (header[0] == '/')
610        {
611          off_t extended_off;
612
613          switch (header[1])
614          {
615            case ' ':
616              /*
617               * Symbols table. Ignore the table.
618               */
619              break;
620            case '/':
621              /*
622               * Extended file names table. Remember.
623               */
624              extended_file_names = offset + rld_archive_fhdr_size;
625              break;
626            case '0':
627            case '1':
628            case '2':
629            case '3':
630            case '4':
631            case '5':
632            case '6':
633            case '7':
634            case '8':
635            case '9':
636              /*
637               * Offset into the extended file name table. If we do not have the
638               * offset to the extended file name table find it.
639               */
640              extended_off = scan_decimal (&header[1], rld_archive_fname_size);
641
642              if (extended_file_names == 0)
643              {
644                off_t off = offset;
645                while (extended_file_names == 0)
646                {
647                  size_t esize =
648                    (scan_decimal (&header[rld_archive_size],
649                                   rld_archive_size_size) + 1) & ~1;
650                  off += esize + rld_archive_fhdr_size;
651
652                  if (!read_header (off, &header[0]))
653                    throw rld::error ("No GNU extended file name section found",
654                                      "get-names:" + name ().path ());
655
656                  if ((header[0] == '/') && (header[1] == '/'))
657                  {
658                    extended_file_names = off + rld_archive_fhdr_size;
659                    break;
660                  }
661                }
662              }
663
664              if (extended_file_names)
665              {
666                /*
667                 * We know the offset in the archive to the extended file. Read
668                 * the name from the table and compare with the name we are
669                 * after.
670                 */
671                char cname[rld_archive_max_file_size];
672                seek_read (extended_file_names + extended_off,
673                           (uint8_t*) &cname[0], rld_archive_max_file_size);
674                add_object (objs, cname,
675                            offset + rld_archive_fhdr_size, size);
676              }
677              break;
678            default:
679              /*
680               * Ignore the file because we do not know what it it.
681               */
682              break;
683          }
684        }
685        else
686        {
687          /*
688           * Normal archive name.
689           */
690          add_object (objs,
691                      (char*) &header[rld_archive_fname],
692                      offset + rld_archive_fhdr_size, size);
693        }
694
695        offset += size + rld_archive_fhdr_size;
696      }
697    }
698
699    bool
700    archive::operator< (const archive& rhs) const
701    {
702      return name ().path () < rhs.name ().path ();
703    }
704
705    bool
706    archive::read_header (off_t offset, uint8_t* header)
707    {
708      if (!seek_read (offset, header, rld_archive_fhdr_size))
709        return false;
710
711      if ((header[rld_archive_magic] != 0x60) ||
712          (header[rld_archive_magic + 1] != 0x0a))
713        throw rld::error ("Invalid header magic numbers at " +
714                          rld::to_string (offset), "read-header:" + name ().path ());
715
716      return true;
717    }
718
719    void
720    archive::add_object (objects& objs, const char* path, off_t offset, size_t size)
721    {
722      const char* end = path;
723      while ((*end != '\0') && (*end != '/') && (*end != '\n'))
724        ++end;
725
726      std::string str;
727      str.append (path, end - path);
728
729      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
730        std::cout << "archive::add-object: " << str << std::endl;
731
732      file n (name ().path (), str, offset, size);
733      objs[n.full()] = new object (*this, n);
734    }
735
736    void
737    archive::write_header (const std::string& name,
738                           uint32_t           mtime,
739                           int                uid,
740                           int                gid,
741                           int                mode,
742                           size_t             size)
743    {
744        uint8_t header[rld_archive_fhdr_size];
745
746        memset (header, ' ', sizeof (header));
747
748        size_t len = name.length ();
749        if (len > rld_archive_fname_size)
750          len = rld_archive_fname_size;
751        memcpy (&header[rld_archive_fname], &name[0], len);
752
753        set_number (mtime, header + rld_archive_mtime, rld_archive_mtime_size);
754        set_number (uid, header + rld_archive_uid, rld_archive_uid_size);
755        set_number (gid, header + rld_archive_gid, rld_archive_gid_size);
756        set_number (mode, header + rld_archive_mode, rld_archive_mode_size, true);
757        set_number (size, header + rld_archive_size, rld_archive_size_size);
758
759        header[rld_archive_magic] = 0x60;
760        header[rld_archive_magic + 1] = 0x0a;
761
762        write (header, sizeof (header));
763    }
764
765    void
766    archive::create (object_list& objects)
767    {
768      if (rld::verbose () >= RLD_VERBOSE_DETAILS)
769        std::cout << "archive::create: " << name ().full ()
770                  << ", objects: " << objects.size () << std::endl;
771
772      open (true);
773
774      try
775      {
776        seek_write (0, rld_archive_ident, rld_archive_ident_size);
777
778        /*
779         * GNU extended filenames.
780         */
781        std::string extended_file_names;
782
783        for (object_list::iterator oi = objects.begin ();
784             oi != objects.end ();
785             ++oi)
786        {
787          object& obj = *(*oi);
788          const std::string&  oname = path::basename (obj.name ().oname ());
789          if (oname.length () >= rld_archive_fname_size)
790            extended_file_names += oname + '\n';
791        }
792
793        if (!extended_file_names.empty ())
794        {
795          if (extended_file_names.length () & 1)
796          {
797            extended_file_names += ' ';
798          }
799          write_header ("//", 0, 0, 0, 0, extended_file_names.length ());
800          write (extended_file_names.c_str (), extended_file_names.length ());
801        }
802
803        for (object_list::iterator oi = objects.begin ();
804             oi != objects.end ();
805             ++oi)
806        {
807          object& obj = *(*oi);
808
809          obj.open ();
810
811          try
812          {
813            std::string oname = path::basename (obj.name ().oname ());
814
815            /*
816             * Convert the file name to an offset into the extended file name
817             * table if the file name is too long for the header.
818             */
819
820            if (oname.length () >= rld_archive_fname_size)
821            {
822              size_t pos = extended_file_names.find (oname + '\n');
823              if (pos == std::string::npos)
824                throw rld_error_at ("extended file name not found");
825              std::ostringstream oss;
826              oss << '/' << pos;
827              oname = oss.str ();
828            }
829            else oname += '/';
830
831            write_header (oname, 0, 0, 0, 0666, (obj.name ().size () + 1) & ~1);
832            obj.seek (0);
833            copy_file (obj, *this);
834            if (obj.name ().size () & 1)
835              write ("\n", 1);
836          }
837          catch (...)
838          {
839            obj.close ();
840            throw;
841          }
842
843          obj.close ();
844        }
845      }
846      catch (...)
847      {
848        close ();
849        throw;
850      }
851
852      close ();
853    }
854
855    relocation::relocation (const elf::relocation& er)
856      : offset (er.offset ()),
857        type (er.type ()),
858        info (er.info ()),
859        addend (er.addend ()),
860        symname (er.symbol ().name ()),
861        symtype (er.symbol ().type ()),
862        symsect (er.symbol ().section_index ()),
863        symvalue (er.symbol ().value ()),
864        symbinding (er.symbol ().binding ())
865    {
866    }
867
868    section::section (const elf::section& es)
869      : name (es.name ()),
870        index (es.index ()),
871        type (es.type ()),
872        size (es.size ()),
873        alignment (es.alignment ()),
874        link (es.link ()),
875        info (es.info ()),
876        flags (es.flags ()),
877        offset (es.offset ()),
878        address (es.address ()),
879        rela (es.get_reloc_type ())
880    {
881    }
882
883    void
884    section::load_relocations (const elf::section& es)
885    {
886      const elf::relocations& es_relocs = es.get_relocations ();
887      for (elf::relocations::const_iterator ri = es_relocs.begin ();
888           ri != es_relocs.end ();
889           ++ri)
890      {
891        relocs.push_back (relocation (*ri));
892      }
893      rela = es.get_reloc_type ();
894    }
895
896    size_t
897    sum_sizes (const sections& secs)
898    {
899      size_t size = 0;
900
901      for (sections::const_iterator si = secs.begin ();
902           si != secs.end ();
903           ++si)
904      {
905        const section& sec = *si;
906
907        if ((size % sec.alignment) != 0)
908          size -= (size % sec.alignment) + sec.alignment;
909        size += sec.size;
910      }
911
912      return size;
913    }
914
915    const section*
916    find (const sections& secs, const int index)
917    {
918      for (sections::const_iterator si = secs.begin ();
919           si != secs.end ();
920           ++si)
921      {
922        const section& sec = *si;
923
924        if (index == sec.index)
925          return &sec;
926      }
927
928      return 0;
929    }
930
931    object::object (archive& archive_, file& name_)
932      : image (name_),
933        archive_ (&archive_),
934        valid_ (false),
935        resolving_ (false),
936        resolved_ (false)
937    {
938      if (!name ().is_valid ())
939        throw rld_error_at ("name is empty");
940    }
941
942    object::object (const std::string& path)
943      : image (path),
944        archive_ (0),
945        valid_ (false),
946        resolving_ (false),
947        resolved_ (false)
948    {
949      if (!name ().is_valid ())
950        throw rld_error_at ("name is empty");
951    }
952
953    object::object ()
954      : archive_ (0),
955        valid_ (false),
956        resolving_ (false),
957        resolved_ (false)
958    {
959    }
960
961    object::~object ()
962    {
963      end ();
964      close ();
965    }
966
967    void
968    object::open (bool writable)
969    {
970      if (archive_)
971      {
972        if (writable)
973          throw rld_error_at ("object files in archives are not writable");
974        archive_->open ();
975      }
976      else
977        image::open (writable);
978    }
979
980    void
981    object::close ()
982    {
983      if (archive_)
984      {
985        archive_->end ();
986        archive_->close ();
987      }
988      else
989      {
990        end ();
991        image::close ();
992      }
993    }
994
995    void
996    object::begin ()
997    {
998      /*
999       * Begin a session.
1000       */
1001
1002      if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
1003        std::cout << "object:begin: " << name ().full () << " in-archive:"
1004                  << ((char*) (archive_ ? "yes" : "no")) << std::endl;
1005
1006      if (archive_)
1007        elf ().begin (name ().full (), archive_->elf(), name ().offset ());
1008      else
1009        elf ().begin (name ().full (), fd (), is_writable ());
1010
1011      /*
1012       * Cannot be an archive.
1013       */
1014      if (elf ().is_archive ())
1015        throw rld::error ("Is an archive not an object file.",
1016                          "object-begin:" + name ().full ());
1017
1018      /*
1019       * We only support executable or relocatable ELF files.
1020       */
1021      if (!is_writable ())
1022      {
1023        if (!elf ().is_executable () && !elf ().is_relocatable ())
1024          throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).",
1025                            "object-begin:" + name ().full ());
1026
1027        elf::check_file (elf ());
1028
1029        /**
1030         * We assume the ELF file is invariant over the linking process.
1031         */
1032
1033        if (secs.empty ())
1034        {
1035          elf::sections elf_secs;
1036
1037          elf ().get_sections (elf_secs, 0);
1038
1039          for (elf::sections::const_iterator esi = elf_secs.begin ();
1040               esi != elf_secs.end ();
1041               ++esi)
1042          {
1043            secs.push_back (section (*(*esi)));
1044          }
1045        }
1046      }
1047
1048      /*
1049       * This is a valid object file. The file format checks out.
1050       */
1051      valid_ = true;
1052    }
1053
1054    void
1055    object::end ()
1056    {
1057      if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
1058        std::cout << "object:end: " << name ().full () << std::endl;
1059
1060      elf ().end ();
1061    }
1062
1063    bool
1064    object::valid () const
1065    {
1066      return valid_;
1067    }
1068
1069    void
1070    object::load_symbols (rld::symbols::table& symbols, bool local)
1071    {
1072      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1073        std::cout << "object:load-sym: " << name ().full () << std::endl;
1074
1075      rld::symbols::pointers syms;
1076
1077      if (local)
1078      {
1079        elf ().get_symbols (syms, false, true, false, false);
1080
1081        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1082          std::cout << "object:load-sym: local: total "
1083                    << syms.size () << std::endl;
1084
1085        for (symbols::pointers::iterator si = syms.begin ();
1086             si != syms.end ();
1087             ++si)
1088        {
1089          symbols::symbol& sym = *(*si);
1090
1091          if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1092            std::cout << "object:load-sym: local: " << sym << std::endl;
1093
1094          sym.set_object (*this);
1095          symbols.add_local (sym);
1096        }
1097      }
1098
1099      elf ().get_symbols (syms, false, false, true, false);
1100
1101      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1102        std::cout << "object:load-sym: weak: total "
1103                  << syms.size () << std::endl;
1104
1105      for (symbols::pointers::iterator si = syms.begin ();
1106           si != syms.end ();
1107           ++si)
1108      {
1109        symbols::symbol& sym = *(*si);
1110
1111        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1112          std::cout << "object:load-sym: weak: " << sym << std::endl;
1113
1114        sym.set_object (*this);
1115        symbols.add_weak (sym);
1116        externals.push_back (&sym);
1117      }
1118
1119      elf ().get_symbols (syms, false, false, false, true);
1120
1121      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1122        std::cout << "object:load-sym: global: total "
1123                  << syms.size () << std::endl;
1124
1125      for (symbols::pointers::iterator si = syms.begin ();
1126           si != syms.end ();
1127           ++si)
1128      {
1129        symbols::symbol& sym = *(*si);
1130
1131        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1132          std::cout << "object:load-sym: global: " << sym << std::endl;
1133
1134        sym.set_object (*this);
1135        symbols.add_global (sym);
1136        externals.push_back (&sym);
1137      }
1138
1139      elf ().get_symbols (syms, true, false, true, true);
1140
1141      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1142        std::cout << "object:load-sym: unresolved: total "
1143                  << syms.size () << std::endl;
1144
1145      for (symbols::pointers::iterator si = syms.begin ();
1146           si != syms.end ();
1147           ++si)
1148      {
1149        symbols::symbol& sym = *(*si);
1150
1151        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1152        {
1153          std::cout << "object:load-sym: unresolved: ";
1154          sym.output (std::cout);
1155          std::cout << std::endl;
1156        }
1157
1158        unresolved[sym.name ()] = &sym;
1159      }
1160    }
1161
1162    void
1163    object::load_relocations ()
1164    {
1165      if (rld::verbose () >= RLD_VERBOSE_TRACE)
1166        std::cout << "object:load-relocs: " << name ().full () << std::endl;
1167
1168      elf ().load_relocations ();
1169
1170      for (sections::iterator si = secs.begin ();
1171           si != secs.end ();
1172           ++si)
1173      {
1174        section&            sec = *si;
1175        const elf::section& elf_sec = elf ().get_section (sec.index);
1176        sec.load_relocations (elf_sec);
1177      }
1178    }
1179
1180    int
1181    object::references () const
1182    {
1183      if (archive_)
1184        return archive_->references ();
1185      return image::references ();
1186    }
1187
1188    size_t
1189    object::size () const
1190    {
1191      if (archive_)
1192        return archive_->size ();
1193      return image::size ();
1194    }
1195
1196    int
1197    object::fd () const
1198    {
1199      if (archive_)
1200        return archive_->fd ();
1201      return image::fd ();
1202    }
1203
1204    void
1205    object::symbol_referenced ()
1206    {
1207      image::symbol_referenced ();
1208      if (archive_)
1209        archive_->symbol_referenced ();
1210    }
1211
1212    archive*
1213    object::get_archive ()
1214    {
1215      return archive_;
1216    }
1217
1218    rld::symbols::symtab&
1219    object::unresolved_symbols ()
1220    {
1221      return unresolved;
1222    }
1223
1224    rld::symbols::pointers&
1225    object::external_symbols ()
1226    {
1227      return externals;
1228    }
1229
1230    void
1231    object::get_sections (sections& filtered_secs,
1232                          uint32_t  type,
1233                          uint64_t  flags_in,
1234                          uint64_t  flags_out)
1235    {
1236      for (sections::const_iterator si = secs.begin ();
1237           si != secs.end ();
1238           ++si)
1239      {
1240        const section& sec = *si;
1241        if ((type == 0) || (type == sec.type))
1242        {
1243          if ((flags_in == 0) ||
1244              (((sec.flags & flags_in) == flags_in) &&
1245               ((sec.flags & flags_out) == 0)))
1246          {
1247            filtered_secs.push_back (sec);
1248          }
1249        }
1250      }
1251    }
1252
1253    void
1254    object::get_sections (sections& filtered_secs, const std::string& matching_name)
1255    {
1256      for (sections::const_iterator si = secs.begin ();
1257           si != secs.end ();
1258           ++si)
1259      {
1260        const section& sec = *si;
1261        if (sec.name == matching_name)
1262        {
1263          filtered_secs.push_back (sec);
1264        }
1265      }
1266    }
1267
1268    const section&
1269    object::get_section (int index) const
1270    {
1271      for (sections::const_iterator si = secs.begin ();
1272           si != secs.end ();
1273           ++si)
1274      {
1275        const section& sec = *si;
1276        if (sec.index == index)
1277          return sec;
1278      }
1279
1280      throw rld::error ("Section index '" + rld::to_string (index) +
1281                        "' not found: " + name ().full (), "object::get-section");
1282    }
1283
1284    void
1285    object::resolve_set ()
1286    {
1287      resolving_ = true;
1288    }
1289
1290    void
1291    object::resolve_clear ()
1292    {
1293      resolving_ = false;
1294    }
1295
1296    bool
1297    object::resolving () const
1298    {
1299      return resolving_;
1300    }
1301
1302    void
1303    object::resolved_set ()
1304    {
1305      resolved_ = true;
1306    }
1307
1308    bool
1309    object::resolved () const
1310    {
1311      return resolved_;
1312    }
1313
1314    cache::cache ()
1315      : opened (false)
1316    {
1317    }
1318
1319    cache::~cache ()
1320    {
1321      close ();
1322    }
1323
1324    void
1325    cache::open ()
1326    {
1327      if (!opened)
1328      {
1329        collect_object_files ();
1330        archives_begin ();
1331        opened = true;
1332      }
1333    }
1334
1335    void
1336    cache::close ()
1337    {
1338      if (opened)
1339      {
1340        /*
1341         * Must delete the object first as they could depend on archives.
1342         */
1343        for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1344          delete (*oi).second;
1345        for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1346          delete (*ai).second;
1347        opened = false;
1348      }
1349    }
1350
1351    void
1352    cache::add (const std::string& path)
1353    {
1354        paths_.push_back (path);
1355        input (path);
1356    }
1357
1358    void
1359    cache::add (path::paths& paths__)
1360    {
1361      for (path::paths::iterator pi = paths__.begin();
1362           pi != paths__.end();
1363           ++pi)
1364        add (*pi);
1365    }
1366
1367    void
1368    cache::add_libraries (path::paths& paths__)
1369    {
1370      for (path::paths::iterator pi = paths__.begin();
1371           pi != paths__.end();
1372           ++pi)
1373        input (*pi);
1374    }
1375
1376    void
1377    cache::archive_begin (const std::string& path)
1378    {
1379      archives::iterator ai = archives_.find (path);
1380      if (ai != archives_.end ())
1381      {
1382        archive* ar = (*ai).second;
1383        if (!ar->is_open ())
1384        {
1385          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1386            std::cout << "cache:archive-begin: " << path << std::endl;
1387          ar->open ();
1388          ar->begin ();
1389        }
1390      }
1391    }
1392
1393    void
1394    cache::archive_end (const std::string& path)
1395    {
1396      archives::iterator ai = archives_.find (path);
1397      if (ai != archives_.end ())
1398      {
1399        archive* ar = (*ai).second;
1400        if (ar->is_open ())
1401        {
1402          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1403            std::cout << "cache:archive-end: " << path << std::endl;
1404          ar->end ();
1405          ar->close ();
1406        }
1407      }
1408    }
1409
1410    void
1411    cache::archives_begin ()
1412    {
1413      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1414        archive_begin (((*ai).second)->path ());
1415    }
1416
1417    void
1418    cache::archives_end ()
1419    {
1420      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1421        archive_end (((*ai).second)->path ());
1422    }
1423
1424    void
1425    cache::collect_object_files ()
1426    {
1427      for (path::paths::iterator ni = paths_.begin (); ni != paths_.end (); ++ni)
1428        collect_object_files (*ni);
1429    }
1430
1431    void
1432    cache::collect_object_files (const std::string& path)
1433    {
1434      archive* ar = new archive (path);
1435
1436      if (ar->is_valid ())
1437      {
1438        try
1439        {
1440          ar->open ();
1441          ar->load_objects (objects_);
1442          ar->close ();
1443          archives_[path] = ar;
1444        }
1445        catch (...)
1446        {
1447          delete ar;
1448          throw;
1449        }
1450      }
1451      else
1452      {
1453        delete ar;
1454        object* obj = new object (path);
1455        if (!obj->name ().exists ())
1456        {
1457          delete obj;
1458          throw rld::error ("'" + path + "', Not found or a regular file.",
1459                            "file-check");
1460        }
1461        try
1462        {
1463          obj->open ();
1464          obj->begin ();
1465          obj->end ();
1466          obj->close ();
1467          objects_[path] = obj;
1468        }
1469        catch (...)
1470        {
1471          delete obj;
1472          throw;
1473        }
1474      }
1475    }
1476
1477    void
1478    cache::load_symbols (rld::symbols::table& symbols, bool local)
1479    {
1480      if (rld::verbose () >= RLD_VERBOSE_INFO)
1481        std::cout << "cache:load-sym: object files: " << objects_.size ()
1482                  << std::endl;
1483
1484      for (objects::iterator oi = objects_.begin ();
1485           oi != objects_.end ();
1486           ++oi)
1487      {
1488        object* obj = (*oi).second;
1489        obj->open ();
1490        obj->begin ();
1491        obj->load_symbols (symbols, local);
1492        obj->end ();
1493        obj->close ();
1494      }
1495
1496      if (rld::verbose () >= RLD_VERBOSE_INFO)
1497        std::cout << "cache:load-sym: symbols: " << symbols.size ()
1498                  << std::endl;
1499    }
1500
1501    void
1502    cache::output_unresolved_symbols (std::ostream& out)
1503    {
1504      for (objects::iterator oi = objects_.begin ();
1505           oi != objects_.end ();
1506           ++oi)
1507      {
1508        object* obj = (*oi).second;
1509        if (obj)
1510        {
1511          out << obj->name ().full () << ':' << std::endl;
1512          rld::symbols::output (out, obj->unresolved_symbols ());
1513        }
1514      }
1515    }
1516
1517    archives&
1518    cache::get_archives ()
1519    {
1520      return archives_;
1521    }
1522
1523    objects&
1524    cache::get_objects ()
1525    {
1526      return objects_;
1527    }
1528
1529    void
1530    cache::get_objects (object_list& list) const
1531    {
1532      list.clear ();
1533      for (path::paths::const_iterator pi = paths_.begin ();
1534           pi != paths_.end ();
1535           ++pi)
1536      {
1537        objects::const_iterator oi = objects_.find (*pi);
1538        if (oi == objects_.end ())
1539          throw rld::error ("Not located or a valid format", *pi);
1540        list.push_back ((*oi).second);
1541      }
1542    }
1543
1544    const path::paths&
1545    cache::get_paths () const
1546    {
1547      return paths_;
1548    }
1549
1550    int
1551    cache::archive_count () const
1552    {
1553      return archives_.size ();
1554    }
1555
1556    int
1557    cache::object_count () const
1558    {
1559      return objects_.size ();
1560    }
1561
1562    int
1563    cache::path_count () const
1564    {
1565      return paths_.size ();
1566    }
1567
1568    void
1569    cache::get_archive_files (files& afiles)
1570    {
1571      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1572        afiles.push_back ((*ai).second->name ().full ());
1573    }
1574
1575    void
1576    cache::get_object_files (files& ofiles)
1577    {
1578      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1579        ofiles.push_back ((*oi).second->name ());
1580    }
1581
1582    void
1583    cache::output_archive_files (std::ostream& out)
1584    {
1585      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1586        out << ' ' << (*ai).second->name ().full () << std::endl;
1587    }
1588
1589    void
1590    cache::output_object_files (std::ostream& out)
1591    {
1592      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1593        out << ' ' << (*oi).second->name ().full () << std::endl;
1594    }
1595
1596    void
1597    cache::input (const std::string& path)
1598    {
1599      if (opened)
1600      {
1601        collect_object_files (path);
1602        archive_begin (path);
1603      }
1604    }
1605
1606    void
1607    find_libraries (path::paths& libraries,
1608                    path::paths& libpaths,
1609                    path::paths& libs)
1610    {
1611      if (rld::verbose () >= RLD_VERBOSE_INFO)
1612        std::cout << "Finding libraries:" << std::endl;
1613      libraries.clear ();
1614      for (path::paths::size_type l = 0; l < libs.size (); ++l)
1615      {
1616        std::string lib = "lib" + libs[l] + ".a";
1617        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
1618          std::cout << " searching: " << lib << std::endl;
1619        bool found = false;
1620        for (path::paths::size_type p = 0; p < libpaths.size (); ++p)
1621        {
1622          std::string plib;
1623          path::path_join (libpaths[p], lib, plib);
1624          if (rld::verbose () >= RLD_VERBOSE_DETAILS)
1625              std::cout << " checking: " << plib << std::endl;
1626          if (path::check_file (plib))
1627          {
1628            if (rld::verbose () >= RLD_VERBOSE_INFO)
1629              std::cout << " found: " << plib << std::endl;
1630            libraries.push_back (plib);
1631            found = true;
1632            break;
1633          }
1634        }
1635
1636        if (!found)
1637          throw rld::error ("Not found", lib);
1638      }
1639    }
1640
1641  }
1642}
Note: See TracBrowser for help on using the repository browser.