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

4.104.115
Last change on this file since b770b0c was b770b0c, checked in by Chris Johns <chrisj@…>, on 11/21/12 at 02:04:19

Make getting objects const.

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