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

4.104.115
Last change on this file since be8e188 was 662c504, checked in by Chris Johns <chrisj@…>, on 11/29/12 at 08:02:28

Add the index to the section.

The index is referenced in the symbol and relocation records of ELF files
therefore we need to search for them.

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