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

4.104.11
Last change on this file since fd8a2c5 was fd8a2c5, checked in by Chris Johns <chrisj@…>, on Nov 20, 2012 at 8:53:24 AM

Add support to write a metadata ELF file.

This also adds support to the ELF classes that wrap libelf. While
this is now done and seems to work I will not be using an ELF
file to hold the metadata after all.

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