source: rtems-tools/rtemstoolkit/rld-files.cpp @ 87e0e76

4.104.115
Last change on this file since 87e0e76 was 87e0e76, checked in by Chris Johns <chrisj@…>, on 09/13/14 at 02:09:16

Refactor code into the RTEMS Toolkit.

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