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

4.104.115
Last change on this file since 065ac15 was 977c3de, checked in by Chris Johns <chrisj@…>, on 11/17/12 at 06:34:33

Refactor the ELF support to allow ELF write suppport.

The refactoring allows better reuse of the ELF support and cleans up
some hacks from the generic file and archive handling improving the
separation of the file handling from the file format, ie ELF. The
handling of ELF object files and ELF object files inside archives
is cleaner.

The refactor cleaned up the symbol handling where the symbols now
reside in the ELF file object and references are take in symbol
pointer containers and symbol table containers.

The main purpose of the refactor is to allow support for creating
and writing ELF files.

Also added an rtems-syms command where special symbol support
can be added.

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