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

4.104.115
Last change on this file since d54e81c was d54e81c, checked in by Chris Johns <chrisj@…>, on 12/15/12 at 12:19:21

Debug trace changes.

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