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

4.104.115
Last change on this file since 596e5fa was 596e5fa, checked in by Chris Johns <chrisj@…>, on 11/18/12 at 23:37:37

Add set_header support to the ELF files.

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