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

4.104.11
Last change on this file since fe19d06 was fe19d06, checked in by Chris Johns <chrisj@…>, on Nov 20, 2012 at 11:40:01 PM

Fix archive GNU extension and make image read/write follow POSIX.

Fix the finding of a file name in the GNU extension for long names
in GNU archives so the correct location is referenced.

Made the image read and write routines keep reading if not all the
requested data is read or written due to possible signals.

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