source: rtems-tools/linkers/rld-files.cpp @ 0b65a28

4.104.115
Last change on this file since 0b65a28 was ec24a37, checked in by Chris Johns <chrisj@…>, on 05/06/12 at 22:47:11

Add to git.

  • Property mode set to 100644
File size: 29.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 <errno.h>
22#include <fcntl.h>
23#include <stdio.h>
24#include <string.h>
25#include <sys/stat.h>
26
27#include <rld.h>
28
29#if __WIN32__
30#define CREATE_MODE (S_IRUSR | S_IWUSR)
31#define OPEN_FLAGS  (O_BINARY)
32#else
33#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
34#define OPEN_FLAGS  (0)
35#endif
36
37namespace rld
38{
39  namespace files
40  {
41    /**
42     * Scan the decimal number returning the value found.
43     */
44    uint64_t
45    scan_decimal (const uint8_t* string, size_t len)
46    {
47      uint64_t value = 0;
48     
49      while (len && (*string != ' '))
50      {
51        value *= 10;
52        value += *string - '0';
53        ++string;
54        --len;
55      }
56
57      return value;
58    }
59
60    void
61    set_number (uint32_t value, uint8_t* string, size_t len, bool octal = false)
62    {
63      std::ostringstream oss;
64      if (octal)
65        oss << std::oct;
66      oss << value;
67      size_t l = oss.str ().length ();
68      if (l > len)
69        l = len;
70      memcpy (string, oss.str ().c_str (), l);
71    }
72
73    std::string
74    basename (const std::string& name)
75    {
76      size_t b = name.find_last_of (RLD_PATH_SEPARATOR);
77      if (b != std::string::npos)
78        return name.substr (b + 1);
79      return name;
80    }
81
82    void
83    path_split (const std::string& path, rld::files::paths& paths)
84    {
85      strings ps;
86      rld::split (path, ps, RLD_PATHSTR_SEPARATOR);
87      if (ps.size ())
88      {
89        for (strings::iterator psi = ps.begin ();
90             psi != ps.end ();
91             ++psi)
92        {
93          if (check_directory (*psi))
94            paths.push_back (*psi);
95        }
96      }
97    }
98
99    void
100    path_join (const std::string& path_, const std::string& file_, std::string& joined)
101    {
102      if ((path_[path_.size () - 1] != RLD_PATH_SEPARATOR) &&
103          (file_[0] != RLD_PATH_SEPARATOR))
104        joined = path_ + RLD_PATH_SEPARATOR + file_;
105      else if ((path_[path_.size () - 1] == RLD_PATH_SEPARATOR) &&
106               (file_[0] == RLD_PATH_SEPARATOR))
107        joined = path_ + &file_[1];       
108      else
109        joined = path_ + file_;
110    }
111
112    bool
113    check_file (const std::string& path)
114    {
115      struct stat sb;
116      if (::stat (path.c_str (), &sb) == 0)
117        if (S_ISREG (sb.st_mode))
118          return true;
119      return false;
120    }
121
122    bool
123    check_directory (const std::string& path)
124    {
125      struct stat sb;
126      if (::stat (path.c_str (), &sb) == 0)
127        if (S_ISDIR (sb.st_mode))
128          return true;
129      return false;
130    }
131
132    void
133    find_file (std::string& path, const std::string& name, paths& search_paths)
134    {
135      for (rld::files::paths::iterator pi = search_paths.begin ();
136           pi != search_paths.end ();
137           ++pi)
138      {
139        path_join (*pi, name, path);
140        if (check_file (path))
141          return;
142      }
143      path.clear ();
144    }
145
146    file::file (const std::string& aname,
147                const std::string& oname,
148                off_t              offset,
149                size_t             size)
150      : aname_ (aname),
151        oname_ (oname),
152        offset_ (offset),
153        size_ (size)
154    {
155    }
156
157    file::file (const std::string& path, bool is_object)
158      : offset_ (0),
159        size_ (0)
160    {
161      set (path, is_object);
162    }
163
164    file::file ()
165      : offset_ (0),
166        size_ (0)
167    {
168    }
169
170    void
171    file::set (const std::string& path, bool is_object)
172    {
173      /*
174       * If there is a path look for a colon. If there is no colon we assume
175       * it is an object file. If the colon is the last character in the path
176       * it is just an archive.
177       */
178      if (!path.empty ())
179      {
180        bool get_size = false;
181        if (is_object)
182        {
183          size_t colon = path.find_last_of (':');
184          if ((colon != std::string::npos) && (colon > RLD_DRIVE_SEPARATOR))
185          {
186            aname_ = path.substr (0, colon - 1);
187            oname_ = path.substr (colon + 1);
188            // @todo Add offset scanning.
189          }
190          else
191          {
192            oname_ = path;
193            get_size = true;
194          }
195        }
196        else
197        {
198          aname_ = path;
199            get_size = true;
200        }
201
202        if (get_size)
203        {
204          struct stat sb;
205          if (::stat (path.c_str (), &sb) == 0)
206            size_ = sb.st_size;
207        }
208      }
209    }
210
211    bool
212    file::is_archive () const
213    {
214      return !aname_.empty () && oname_.empty ();
215    }
216
217    bool
218    file::is_object () const
219    {
220      return !oname_.empty ();
221    }
222
223    bool
224    file::is_valid () const
225    {
226      return !aname_.empty () || ~oname_.empty ();
227    }
228
229    bool
230    file::exists () const
231    {
232      /*
233       * No name set returns false.
234       */
235      bool result = false;
236      const std::string p = path ();
237      if (!p.empty ())
238        result = check_file (p);
239      return result;
240    }
241
242    const std::string
243    file::path () const
244    {
245      if (!aname_.empty ())
246        return aname_;
247      return oname_;
248    }
249   
250    const std::string
251    file::full () const
252    {
253      std::string f;
254      if (!aname_.empty ())
255      {
256        f = aname_;
257        if (!oname_.empty ())
258          f += ':';
259      }
260      if (!oname_.empty ())
261        f += oname_;
262      if (!aname_.empty () && !oname_.empty ())
263        f += '@' + rld::to_string (offset_);
264      return f;
265    }
266
267    const std::string
268    file::basename () const
269    {
270      return rld::files::basename (full ());
271    }
272
273    const std::string&
274    file::aname () const
275    {
276      return aname_;
277    }
278
279    const std::string&
280    file::oname () const
281    {
282      return oname_;
283    }
284
285    off_t
286    file::offset () const
287    {
288       return offset_;
289    }
290
291    size_t
292    file::size () const
293    {
294       return size_;
295    }
296
297    image::image (file& name)
298      : name_ (name),
299        references_ (0),
300        fd_ (-1),
301        elf_ (0)
302    {
303    }
304
305    image::image (const std::string& path, bool is_object)
306      : name_ (path, is_object),
307        references_ (0),
308        fd_ (-1),
309        elf_ (0),
310        symbol_refs (0)
311    {
312    }
313
314    image::image ()
315      : references_ (0),
316        fd_ (-1),
317        elf_ (0),
318        symbol_refs (0)
319    {
320    }
321
322    image::~image ()
323    {
324      if (references_)
325        throw rld_error_at ("references when destructing image");
326      if (fd_ >= 0)
327        ::close (fd_);
328    }
329
330    void
331    image::open (file& name)
332    {
333      name_ = name;
334      open ();
335    }
336
337    void
338    image::open (bool writable)
339    {
340      const std::string path = name_.path ();
341
342      if (path.empty ())
343        throw rld::error ("No file name", "open" + path);
344
345      if (rld::verbose () >= RLD_VERBOSE_DETAILS)
346        std::cout << "image::open: " << name (). full ()
347                  << " refs:" << references_ + 1 << std::endl;
348
349      if (fd_ < 0)
350      {
351        if (writable)
352          fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDWR | O_CREAT | O_TRUNC, CREATE_MODE);
353        else
354          fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDONLY);
355        if (fd_ < 0)
356          throw rld::error (::strerror (errno), "open:" + path);
357      }
358
359      ++references_;
360    }
361
362    void
363    image::close ()
364    {
365      if (references_ > 0)
366      {
367        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
368          std::cout << "image::close: " << name ().full ()
369                    << " refs:" << references_ << std::endl;
370
371        --references_;
372        if (references_ == 0)
373        {
374          ::close (fd_);
375          fd_ = -1;
376        }
377      }
378    }
379
380    ssize_t
381    image::read (uint8_t* buffer, size_t size)
382    {
383      ssize_t rsize = ::read (fd (), buffer, size);
384      if (rsize < 0)
385        throw rld::error (strerror (errno), "read:" + name ().path ());
386      return rsize;
387    }
388 
389    ssize_t
390    image::write (const void* buffer, size_t size)
391    {
392      ssize_t wsize = ::write (fd (), buffer, size);
393      if (wsize < 0)
394        throw rld::error (strerror (errno), "write:" + name ().path ());
395      return wsize;
396    }
397 
398    void
399    image::seek (off_t offset)
400    {
401      if (::lseek (fd (), name_.offset () + offset, SEEK_SET) < 0)
402        throw rld::error (strerror (errno), "lseek:" + name ().path ());
403    }
404 
405    bool
406    image::seek_read (off_t offset, uint8_t* buffer, size_t size)
407    {
408      seek (offset);
409      return size == (size_t) read (buffer, size);
410    }
411 
412    bool
413    image::seek_write (off_t offset, const void* buffer, size_t size)
414    {
415      seek (offset);
416      return size == (size_t) write (buffer, size);
417    }
418 
419    const file&
420    image::name () const
421    {
422      return name_;
423    }
424
425    int
426    image::references () const
427    {
428      return references_;
429    }
430
431    size_t
432    image::size () const
433    {
434      return name ().size ();
435    }
436
437    int
438    image::fd () const
439    {
440      return fd_;
441    }
442
443    rld::elf::elf*
444    image::elf (bool )
445    {
446      return elf_;
447    }
448
449    void
450    image::set_elf (rld::elf::elf* elf)
451    {
452      elf_ = elf;
453    }
454
455    void
456    image::symbol_referenced ()
457    {
458      ++symbol_refs;
459    }
460   
461    int
462    image::symbol_references () const
463    {
464      return symbol_refs;
465    }
466
467    void
468    copy_file (image& in, image& out, size_t size)
469    {
470      #define COPY_FILE_BUFFER_SIZE (8 * 1024)
471      uint8_t* buffer = 0;
472      try
473      {
474        buffer = new uint8_t[COPY_FILE_BUFFER_SIZE];
475        while (size)
476        {
477          size_t l = size < COPY_FILE_BUFFER_SIZE ? size : COPY_FILE_BUFFER_SIZE;
478          ssize_t r = ::read (in.fd (), buffer, l);
479
480          if (r < 0)
481            throw rld::error (::strerror (errno), "reading: " + in.name ().full ());
482
483          if (r == 0)
484          {
485            std::ostringstream oss;
486            oss << "reading: " + in.name ().full () << " (" << size << ')';
487            throw rld::error ("input too short", oss.str ());
488          }
489
490          ssize_t w = ::write (out.fd (), buffer, r);
491
492          if (w < 0)
493            throw rld::error (::strerror (errno), "writing: " + out.name ().full ());
494
495          if (w != r)
496            throw rld::error ("output trucated", "writing: " + out.name ().full ());
497
498          size -= r;
499        }
500      }
501      catch (...)
502      {
503        delete [] buffer;
504        throw;
505      }
506
507      if (buffer)
508        delete [] buffer;
509    }
510
511    /**
512     * Defines for the header of an archive.
513     */
514    #define rld_archive_ident         "!<arch>\n"
515    #define rld_archive_ident_size    (sizeof (rld_archive_ident) - 1)
516    #define rld_archive_fhdr_base     rld_archive_ident_size
517    #define rld_archive_fname         (0)
518    #define rld_archive_fname_size    (16)
519    #define rld_archive_mtime         (16)
520    #define rld_archive_mtime_size    (12)
521    #define rld_archive_uid           (28)
522    #define rld_archive_uid_size      (6)
523    #define rld_archive_gid           (34)
524    #define rld_archive_gid_size      (6)
525    #define rld_archive_mode          (40)
526    #define rld_archive_mode_size     (8)
527    #define rld_archive_size          (48)
528    #define rld_archive_size_size     (10)
529    #define rld_archive_magic         (58)
530    #define rld_archive_magic_size    (2)
531    #define rld_archive_fhdr_size     (60)
532    #define rld_archive_max_file_size (1024)
533
534    archive::archive (const std::string& path)
535      : image (path, false)
536    {
537      if (!name ().is_valid ())
538        throw rld_error_at ("name is empty");
539      if (!name ().is_archive ())
540        throw rld_error_at ("name is not an archive: " + name ().oname ());
541    }
542
543    archive::~archive ()
544    {
545      close ();
546    }
547
548    bool
549    archive::is (const std::string& path) const
550    {
551      return name ().path () == path;
552    }
553
554    bool
555    archive::is_valid ()
556    {
557      open ();
558      uint8_t header[rld_archive_ident_size];
559      seek_read (0, &header[0], rld_archive_ident_size);
560      bool result = ::memcmp (header, rld_archive_ident,
561                              rld_archive_ident_size) == 0 ? true : false;
562      close ();
563      return result;
564    }
565
566    void
567    archive::load_objects (objects& objs)
568    {
569      off_t extended_file_names = 0;
570      off_t offset = rld_archive_fhdr_base;
571      size_t size = 0;
572
573      while (true)
574      {
575        uint8_t header[rld_archive_fhdr_size];
576
577        if (!read_header (offset, &header[0]))
578          break;
579
580        /*
581         * The archive file headers are always aligned to an even address.
582         */
583        size =
584          (scan_decimal (&header[rld_archive_size],
585                         rld_archive_size_size) + 1) & ~1;
586
587        /*
588         * Check for the GNU extensions.
589         */
590        if (header[0] == '/')
591        {
592          off_t extended_off;
593
594          switch (header[1])
595          {
596            case ' ':
597              /*
598               * Symbols table. Ignore the table.
599               */
600              break;
601            case '/':
602              /*
603               * Extended file names table. Remember.
604               */
605              extended_file_names = offset + rld_archive_fhdr_size;
606              break;
607            case '0':
608            case '1':
609            case '2':
610            case '3':
611            case '4':
612            case '5':
613            case '6':
614            case '7':
615            case '8':
616            case '9':
617              /*
618               * Offset into the extended file name table. If we do not have the
619               * offset to the extended file name table find it.
620               */
621              extended_off = scan_decimal (&header[1], rld_archive_fname_size);
622
623              if (extended_file_names == 0)
624              {
625                off_t off = offset;
626                while (extended_file_names == 0)
627                {
628                  size_t esize =
629                    (scan_decimal (&header[rld_archive_size],
630                                   rld_archive_size_size) + 1) & ~1;
631                  off += esize + rld_archive_fhdr_size;
632                   
633                  if (!read_header (off, &header[0]))
634                    throw rld::error ("No GNU extended file name section found",
635                                      "get-names:" + name ().path ());
636             
637                  if ((header[0] == '/') && (header[1] == '/'))
638                  {
639                    extended_file_names = off + rld_archive_fhdr_size;
640                    break;
641                  }
642                }
643              }
644
645              if (extended_file_names)
646              {
647                /*
648                 * We know the offset in the archive to the extended file. Read
649                 * the name from the table and compare with the name we are
650                 * after.
651                 */
652                char cname[rld_archive_max_file_size];
653                seek_read (extended_file_names + extended_off,
654                           (uint8_t*) &cname[0], rld_archive_max_file_size);
655                add_object (objs, cname,
656                            offset + rld_archive_fhdr_size, size);
657              }
658              break;
659            default:
660              /*
661               * Ignore the file because we do not know what it it.
662               */
663              break;
664          }
665        }
666        else
667        {
668          /*
669           * Normal archive name.
670           */
671          add_object (objs,
672                      (char*) &header[rld_archive_fname],
673                      offset + rld_archive_fhdr_size, size);
674        }
675
676        offset += size + rld_archive_fhdr_size;
677      }
678    }
679
680    bool
681    archive::operator< (const archive& rhs) const
682    {
683      return name ().path () < rhs.name ().path ();
684    }
685
686    bool
687    archive::read_header (off_t offset, uint8_t* header)
688    {
689      if (!seek_read (offset, header, rld_archive_fhdr_size))
690        return false;
691
692      if ((header[rld_archive_magic] != 0x60) ||
693          (header[rld_archive_magic + 1] != 0x0a))
694        throw rld::error ("Invalid header magic numbers at " +
695                          rld::to_string (offset), "read-header:" + name ().path ());
696     
697      return true;
698    }
699
700    void
701    archive::add_object (objects& objs, const char* path, off_t offset, size_t size)
702    {
703      const char* end = path;
704      while ((*end != '\0') && (*end != '/'))
705        ++end;
706
707      std::string str;
708      str.append (path, end - path);
709
710      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
711        std::cout << "archive::add-object: " << str << std::endl;
712
713      file n (name ().path (), str, offset, size);
714      objs[n.full()] = new object (*this, n);
715    }
716
717    void
718    archive::write_header (const std::string& name,
719                           uint32_t           mtime,
720                           int                uid,
721                           int                gid,
722                           int                mode,
723                           size_t             size)
724    {
725        uint8_t header[rld_archive_fhdr_size];
726
727        memset (header, ' ', sizeof (header));
728       
729        size_t len = name.length ();
730        if (len > rld_archive_fname_size)
731          len = rld_archive_fname_size;
732        memcpy (&header[rld_archive_fname], &name[0], len);
733
734        set_number (mtime, header + rld_archive_mtime, rld_archive_mtime_size);
735        set_number (uid, header + rld_archive_uid, rld_archive_uid_size);
736        set_number (gid, header + rld_archive_gid, rld_archive_gid_size);
737        set_number (mode, header + rld_archive_mode, rld_archive_mode_size, true);
738        set_number (size, header + rld_archive_size, rld_archive_size_size);
739
740        header[rld_archive_magic] = 0x60;
741        header[rld_archive_magic + 1] = 0x0a;
742
743        write (header, sizeof (header));
744    }
745
746    void
747    archive::create (object_list& objects)
748    {
749      open (true);
750
751      try
752      {
753        seek_write (0, rld_archive_ident, rld_archive_ident_size);
754
755        /*
756         * GNU extended filenames.
757         */
758        std::string extended_file_names;
759       
760        for (object_list::iterator oi = objects.begin ();
761             oi != objects.end ();
762             ++oi)
763        {
764          object& obj = *(*oi);
765          const std::string&  oname = basename (obj.name ().oname ());
766          if (oname.length () > rld_archive_fname_size)
767            extended_file_names += oname + '\n';
768        }
769
770        if (!extended_file_names.empty ())
771        {
772          write_header ("//", 0, 0, 0, 0, extended_file_names.length ());
773          write (extended_file_names.c_str (), extended_file_names.length ());
774        }
775
776        for (object_list::iterator oi = objects.begin ();
777             oi != objects.end ();
778             ++oi)
779        {
780          object& obj = *(*oi);
781
782          obj.open ();
783
784          try
785          {
786            std::string oname = basename (obj.name ().oname ());
787
788            /*
789             * Convert the file name to an offset into the extended file name
790             * table if the file name is too long for the header.
791             */
792
793            if (oname.length () > rld_archive_fname_size)
794            {
795              size_t pos = extended_file_names.find_first_of (oname + '\n');
796              if (pos == std::string::npos)
797                throw rld_error_at ("extended file name not found");
798              std::ostringstream oss;
799              oss << '/' << pos;
800              oname = oss.str ();
801            }
802
803            write_header (oname, 0, 0, 0, 0666, obj.name ().size ());
804            obj.seek (0);
805            copy_file (obj, *this, obj.name ().size ());
806          }
807          catch (...)
808          {
809            obj.close ();
810            throw;
811          }
812
813          obj.close ();
814        }
815      }
816      catch (...)
817      {
818        close ();
819        throw;
820      }
821     
822      close ();
823    }
824
825    object::object (archive& archive_, file& name_)
826      : image (name_),
827        archive_ (&archive_)
828    {
829      if (!name ().is_valid ())
830        throw rld_error_at ("name is empty");
831    }
832
833    object::object (const std::string& path)
834      : image (path),
835        archive_ (0)
836    {
837      if (!name ().is_valid ())
838        throw rld_error_at ("name is empty");
839    }
840
841    object::object ()
842      : archive_ (0)
843    {
844    }
845
846    object::~object ()
847    {
848      end ();
849      close ();
850    }
851
852    void
853    object::open ()
854    {
855      if (rld::verbose () >= RLD_VERBOSE_TRACE)
856        std::cout << "object::open: " << name ().full () << std::endl;
857
858      if (archive_)
859        archive_->open ();
860      else
861        image::open ();
862    }
863
864    void
865    object::close ()
866    {
867      if (rld::verbose () >= RLD_VERBOSE_TRACE)
868        std::cout << "object::close: " << name ().full () << std::endl;
869
870      if (archive_)
871        archive_->close ();
872      else
873        image::close ();
874    }
875
876    void
877    object::begin ()
878    {
879      /*
880       * Begin an ELF session and get the ELF header.
881       */
882      rld::elf::begin (*this);
883      rld::elf::get_header (*this, ehdr);
884    }
885
886    void
887    object::end ()
888    {
889      rld::elf::end (*this);
890    }
891
892    void
893    object::load_symbols (rld::symbols::table& symbols, bool local)
894    {
895      if (rld::verbose () >= RLD_VERBOSE_DETAILS)
896        std::cout << "object:load-sym: " << name ().full () << std::endl;
897      rld::elf::load_symbols (symbols, *this, local);
898    }
899
900    std::string
901    object::get_string (int section, size_t offset)
902    {
903      return rld::elf::get_string (*this, section, offset);
904    }
905   
906    int
907    object::references () const
908    {
909      if (archive_)
910        return archive_->references ();
911      return image::references ();
912    }
913
914    size_t
915    object::size () const
916    {
917      if (archive_)
918        return archive_->size ();
919      return image::size ();
920    }
921
922    int
923    object::fd () const
924    {
925      if (archive_)
926        return archive_->fd ();
927      return image::fd ();
928    }
929
930    rld::elf::elf*
931    object::elf (bool archive__)
932    {
933      if (archive__ && archive_)
934        return archive_->elf ();
935      return image::elf ();
936    }
937
938    void
939    object::symbol_referenced ()
940    {
941      image::symbol_referenced ();
942      if (archive_)
943        archive_->symbol_referenced ();
944    }
945   
946    archive*
947    object::get_archive ()
948    {
949      return archive_;
950    }
951
952    int
953    object::sections () const
954    {
955      return ehdr.e_shnum;
956    }
957
958    int
959    object::section_strings () const
960    {
961      return ehdr.e_shstrndx;
962    }
963
964    rld::symbols::table&
965    object::unresolved_symbols ()
966    {
967      return unresolved;
968    }
969
970    rld::symbols::list&
971    object::external_symbols ()
972    {
973      return externals;
974    }
975
976    cache::cache ()
977      : opened (false)
978    {
979    }
980
981    cache::~cache ()
982    {
983      close ();
984    }
985
986    void
987    cache::open ()
988    {
989      if (!opened)
990      {
991        collect_object_files ();
992        archives_begin ();
993        opened = true;
994      }
995    }
996
997    void
998    cache::close ()
999    {
1000      if (opened)
1001      {
1002        /*
1003         * Must delete the object first as they could depend on archives.
1004         */
1005        for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1006          delete (*oi).second;
1007        for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1008          delete (*ai).second;
1009        opened = false;
1010      }
1011    }
1012
1013    void
1014    cache::add (const std::string& path)
1015    {
1016        paths_.push_back (path);
1017        input (path);
1018    }
1019
1020    void
1021    cache::add (paths& paths__)
1022    {
1023      for (paths::iterator pi = paths__.begin();
1024           pi != paths__.end();
1025           ++pi)
1026        add (*pi);
1027    }
1028
1029    void
1030    cache::add_libraries (paths& paths__)
1031    {
1032      for (paths::iterator pi = paths__.begin();
1033           pi != paths__.end();
1034           ++pi)
1035        input (*pi);
1036    }
1037
1038    void
1039    cache::archive_begin (const std::string& path)
1040    {
1041      archives::iterator ai = archives_.find (path);
1042      if (ai != archives_.end ())
1043      {
1044        archive* ar = (*ai).second;
1045        if (!ar->is_open ())
1046        {
1047          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1048            std::cout << "cache:archive-begin: " << path << std::endl;
1049          ar->open ();
1050          rld::elf::begin (*ar);
1051        }
1052      }
1053    }
1054
1055    void
1056    cache::archive_end (const std::string& path)
1057    {
1058      archives::iterator ai = archives_.find (path);
1059      if (ai != archives_.end ())
1060      {
1061        archive* ar = (*ai).second;
1062        if (ar->is_open ())
1063        {
1064          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1065            std::cout << "cache:archive-end: " << path << std::endl;
1066          rld::elf::end (*ar);
1067          ar->close ();
1068        }
1069      }
1070    }
1071
1072    void
1073    cache::archives_begin ()
1074    {
1075      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1076        archive_begin (((*ai).second)->path ());
1077    }
1078
1079    void
1080    cache::archives_end ()
1081    {
1082      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1083        archive_end (((*ai).second)->path ());
1084    }
1085   
1086    void
1087    cache::collect_object_files ()
1088    {
1089      for (paths::iterator ni = paths_.begin (); ni != paths_.end (); ++ni)
1090        collect_object_files (*ni);
1091    }
1092
1093    void
1094    cache::collect_object_files (const std::string& path)
1095    {
1096      archive* ar = new archive (path);
1097
1098      if (ar->is_valid ())
1099      {
1100        try
1101        {
1102          archives_[path] = ar;
1103          ar->open ();
1104          ar->load_objects (objects_);
1105          ar->close ();
1106        }
1107        catch (...)
1108        {
1109          delete ar;
1110          throw;
1111        }
1112      }
1113      else
1114      {
1115        delete ar;
1116        object* obj = new object (path);
1117        if (!obj->name ().exists ())
1118        {
1119          delete obj;
1120          throw rld::error ("'" + path + "', Not found or a regular file.",
1121                            "file-check");
1122        }
1123        try
1124        {
1125          obj->open ();
1126          obj->begin ();
1127          obj->end ();
1128          obj->close ();
1129          objects_[path] = obj;
1130        }
1131        catch (...)
1132        {
1133          delete obj;
1134          throw;
1135        }
1136      }
1137    }
1138
1139    void
1140    cache::load_symbols (rld::symbols::table& symbols, bool local)
1141    {
1142      for (objects::iterator oi = objects_.begin ();
1143           oi != objects_.end ();
1144           ++oi)
1145      {
1146        object* obj = (*oi).second;
1147        obj->open ();
1148        obj->begin ();
1149        obj->load_symbols (symbols, local);
1150        obj->end ();
1151        obj->close ();
1152      }
1153    }
1154
1155    void
1156    cache::output_unresolved_symbols (std::ostream& out)
1157    {
1158      for (objects::iterator oi = objects_.begin ();
1159           oi != objects_.end ();
1160           ++oi)
1161      {
1162        object* obj = (*oi).second;
1163        if (obj)
1164        {
1165          out << obj->name ().full () << ':' << std::endl;
1166          rld::symbols::output (out, obj->unresolved_symbols ());
1167        }
1168      }
1169    }
1170
1171    archives&
1172    cache::get_archives ()
1173    {
1174      return archives_;
1175    }
1176 
1177    objects&
1178    cache::get_objects ()
1179    {
1180      return objects_;
1181    }
1182
1183    void
1184    cache::get_objects (object_list& list)
1185    {
1186      list.clear ();
1187      for (paths::iterator pi = paths_.begin ();
1188           pi != paths_.end ();
1189           ++pi)
1190      {
1191        objects::iterator oi = objects_.find (*pi);
1192        if (oi == objects_.end ())
1193          throw rld_error_at ("path not found in objects");
1194        list.push_back ((*oi).second);
1195      }
1196    }
1197
1198    const paths&
1199    cache::get_paths () const
1200    {
1201      return paths_;
1202    }
1203
1204    int
1205    cache::archive_count () const
1206    {
1207      return archives_.size ();
1208    }
1209
1210    int
1211    cache::object_count () const
1212    {
1213      return objects_.size ();
1214    }
1215
1216    int
1217    cache::path_count () const
1218    {
1219      return paths_.size ();
1220    }
1221
1222    void
1223    cache::get_archive_files (files& afiles)
1224    {
1225      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1226        afiles.push_back ((*ai).second->name ().full ());
1227    }
1228
1229    void
1230    cache::get_object_files (files& ofiles)
1231    {
1232      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1233        ofiles.push_back ((*oi).second->name ());
1234    }
1235
1236    void
1237    cache::output_archive_files (std::ostream& out)
1238    {
1239      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1240        out << ' ' << (*ai).second->name ().full () << std::endl;
1241    }
1242
1243    void
1244    cache::output_object_files (std::ostream& out)
1245    {
1246      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1247        out << ' ' << (*oi).second->name ().full () << std::endl;
1248    }
1249
1250    void
1251    cache::input (const std::string& path)
1252    {
1253      if (opened)
1254      {
1255        collect_object_files (path);
1256        archive_begin (path);
1257      }
1258    }
1259
1260    void
1261    find_libraries (paths& libraries, paths& libpaths, paths& libs)
1262    {
1263      if (rld::verbose () >= RLD_VERBOSE_INFO)
1264        std::cout << "Finding libraries:" << std::endl;
1265      libraries.clear ();
1266      for (paths::size_type l = 0; l < libs.size (); ++l)
1267      {
1268        std::string lib = "lib" + libs[l] + ".a";
1269        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
1270          std::cout << "searching: " << lib << std::endl;
1271        bool found = false;
1272        for (paths::size_type p = 0; p < libpaths.size (); ++p)
1273        {
1274          std::string plib;
1275          path_join (libpaths[p], lib, plib);
1276          if (rld::verbose () >= RLD_VERBOSE_DETAILS)
1277              std::cout << "checking: " << plib << std::endl;
1278          if (check_file (plib))
1279          {
1280            if (rld::verbose () >= RLD_VERBOSE_INFO)
1281              std::cout << "found: " << plib << std::endl;
1282            libraries.push_back (plib);
1283            found = true;
1284            break;
1285          }
1286        }
1287
1288        if (!found)
1289          throw rld::error ("Not found", lib);
1290      }
1291    }
1292
1293  }
1294}
Note: See TracBrowser for help on using the repository browser.