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

4.104.115
Last change on this file since 2ce23a3 was 2ce23a3, checked in by Chris Johns <chrisj@…>, on 08/01/14 at 06:47:11

Fix building on Windows with the latest MSVC.

Remove some warnings.

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