source: rtems-tools/rtemstoolkit/rld-files.cpp @ 0c0b2d4

4.105
Last change on this file since 0c0b2d4 was 066a64b, checked in by Chris Johns <chrisj@…>, on 11/08/14 at 06:59:40

toolkit: Raise a user error and not an internal one.

  • Property mode set to 100644
File size: 38.0 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      if (local)
1044      {
1045        elf ().get_symbols (syms, false, true, false, false);
1046
1047        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1048          std::cout << "object:load-sym: local: total "
1049                    << syms.size () << std::endl;
1050
1051        for (symbols::pointers::iterator si = syms.begin ();
1052             si != syms.end ();
1053             ++si)
1054        {
1055          symbols::symbol& sym = *(*si);
1056
1057          if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1058            std::cout << "object:load-sym: local: " << sym << std::endl;
1059
1060          sym.set_object (*this);
1061          symbols.add_local (sym);
1062        }
1063      }
1064
1065      elf ().get_symbols (syms, false, false, true, false);
1066
1067      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1068        std::cout << "object:load-sym: weak: total "
1069                  << syms.size () << std::endl;
1070
1071      for (symbols::pointers::iterator si = syms.begin ();
1072           si != syms.end ();
1073           ++si)
1074      {
1075        symbols::symbol& sym = *(*si);
1076
1077        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1078          std::cout << "object:load-sym: weak: " << sym << std::endl;
1079
1080        sym.set_object (*this);
1081        symbols.add_weak (sym);
1082        externals.push_back (&sym);
1083      }
1084
1085      elf ().get_symbols (syms, false, false, false, true);
1086
1087      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1088        std::cout << "object:load-sym: global: total "
1089                  << syms.size () << std::endl;
1090
1091      for (symbols::pointers::iterator si = syms.begin ();
1092           si != syms.end ();
1093           ++si)
1094      {
1095        symbols::symbol& sym = *(*si);
1096
1097        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1098          std::cout << "object:load-sym: global: " << sym << std::endl;
1099
1100        sym.set_object (*this);
1101        symbols.add_global (sym);
1102        externals.push_back (&sym);
1103      }
1104
1105      elf ().get_symbols (syms, true, false, true, true);
1106
1107      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1108        std::cout << "object:load-sym: unresolved: total "
1109                  << syms.size () << std::endl;
1110
1111      for (symbols::pointers::iterator si = syms.begin ();
1112           si != syms.end ();
1113           ++si)
1114      {
1115        symbols::symbol& sym = *(*si);
1116
1117        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1118        {
1119          std::cout << "object:load-sym: unresolved: ";
1120          sym.output (std::cout);
1121          std::cout << std::endl;
1122        }
1123
1124        unresolved[sym.name ()] = &sym;
1125      }
1126    }
1127
1128    void
1129    object::load_relocations ()
1130    {
1131      if (rld::verbose () >= RLD_VERBOSE_TRACE)
1132        std::cout << "object:load-relocs: " << name ().full () << std::endl;
1133
1134      elf ().load_relocations ();
1135
1136      for (sections::iterator si = secs.begin ();
1137           si != secs.end ();
1138           ++si)
1139      {
1140        section&            sec = *si;
1141        const elf::section& elf_sec = elf ().get_section (sec.index);
1142        sec.load_relocations (elf_sec);
1143      }
1144    }
1145
1146    int
1147    object::references () const
1148    {
1149      if (archive_)
1150        return archive_->references ();
1151      return image::references ();
1152    }
1153
1154    size_t
1155    object::size () const
1156    {
1157      if (archive_)
1158        return archive_->size ();
1159      return image::size ();
1160    }
1161
1162    int
1163    object::fd () const
1164    {
1165      if (archive_)
1166        return archive_->fd ();
1167      return image::fd ();
1168    }
1169
1170    void
1171    object::symbol_referenced ()
1172    {
1173      image::symbol_referenced ();
1174      if (archive_)
1175        archive_->symbol_referenced ();
1176    }
1177
1178    archive*
1179    object::get_archive ()
1180    {
1181      return archive_;
1182    }
1183
1184    rld::symbols::symtab&
1185    object::unresolved_symbols ()
1186    {
1187      return unresolved;
1188    }
1189
1190    rld::symbols::pointers&
1191    object::external_symbols ()
1192    {
1193      return externals;
1194    }
1195
1196    void
1197    object::get_sections (sections& filtered_secs,
1198                          uint32_t  type,
1199                          uint64_t  flags_in,
1200                          uint64_t  flags_out)
1201    {
1202      for (sections::const_iterator si = secs.begin ();
1203           si != secs.end ();
1204           ++si)
1205      {
1206        const section& sec = *si;
1207        if ((type == 0) || (type == sec.type))
1208        {
1209          if ((flags_in == 0) ||
1210              (((sec.flags & flags_in) == flags_in) &&
1211               ((sec.flags & flags_out) == 0)))
1212          {
1213            filtered_secs.push_back (sec);
1214          }
1215        }
1216      }
1217    }
1218
1219    void
1220    object::get_sections (sections& filtered_secs, const std::string& matching_name)
1221    {
1222      for (sections::const_iterator si = secs.begin ();
1223           si != secs.end ();
1224           ++si)
1225      {
1226        const section& sec = *si;
1227        if (sec.name == matching_name)
1228        {
1229          filtered_secs.push_back (sec);
1230        }
1231      }
1232    }
1233
1234    const section&
1235    object::get_section (int index) const
1236    {
1237      for (sections::const_iterator si = secs.begin ();
1238           si != secs.end ();
1239           ++si)
1240      {
1241        const section& sec = *si;
1242        if (sec.index == index)
1243          return sec;
1244      }
1245
1246      throw rld::error ("Section index '" + rld::to_string (index) +
1247                        "' not found: " + name ().full (), "object::get-section");
1248    }
1249
1250    void
1251    object::resolve_set ()
1252    {
1253      resolving_ = true;
1254    }
1255
1256    void
1257    object::resolve_clear ()
1258    {
1259      resolving_ = false;
1260    }
1261
1262    bool
1263    object::resolving () const
1264    {
1265      return resolving_;
1266    }
1267
1268    void
1269    object::resolved_set ()
1270    {
1271      resolved_ = true;
1272    }
1273
1274    bool
1275    object::resolved () const
1276    {
1277      return resolved_;
1278    }
1279
1280    cache::cache ()
1281      : opened (false)
1282    {
1283    }
1284
1285    cache::~cache ()
1286    {
1287      close ();
1288    }
1289
1290    void
1291    cache::open ()
1292    {
1293      if (!opened)
1294      {
1295        collect_object_files ();
1296        archives_begin ();
1297        opened = true;
1298      }
1299    }
1300
1301    void
1302    cache::close ()
1303    {
1304      if (opened)
1305      {
1306        /*
1307         * Must delete the object first as they could depend on archives.
1308         */
1309        for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1310          delete (*oi).second;
1311        for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1312          delete (*ai).second;
1313        opened = false;
1314      }
1315    }
1316
1317    void
1318    cache::add (const std::string& path)
1319    {
1320        paths_.push_back (path);
1321        input (path);
1322    }
1323
1324    void
1325    cache::add (path::paths& paths__)
1326    {
1327      for (path::paths::iterator pi = paths__.begin();
1328           pi != paths__.end();
1329           ++pi)
1330        add (*pi);
1331    }
1332
1333    void
1334    cache::add_libraries (path::paths& paths__)
1335    {
1336      for (path::paths::iterator pi = paths__.begin();
1337           pi != paths__.end();
1338           ++pi)
1339        input (*pi);
1340    }
1341
1342    void
1343    cache::archive_begin (const std::string& path)
1344    {
1345      archives::iterator ai = archives_.find (path);
1346      if (ai != archives_.end ())
1347      {
1348        archive* ar = (*ai).second;
1349        if (!ar->is_open ())
1350        {
1351          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1352            std::cout << "cache:archive-begin: " << path << std::endl;
1353          ar->open ();
1354          ar->begin ();
1355        }
1356      }
1357    }
1358
1359    void
1360    cache::archive_end (const std::string& path)
1361    {
1362      archives::iterator ai = archives_.find (path);
1363      if (ai != archives_.end ())
1364      {
1365        archive* ar = (*ai).second;
1366        if (ar->is_open ())
1367        {
1368          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1369            std::cout << "cache:archive-end: " << path << std::endl;
1370          ar->end ();
1371          ar->close ();
1372        }
1373      }
1374    }
1375
1376    void
1377    cache::archives_begin ()
1378    {
1379      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1380        archive_begin (((*ai).second)->path ());
1381    }
1382
1383    void
1384    cache::archives_end ()
1385    {
1386      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1387        archive_end (((*ai).second)->path ());
1388    }
1389
1390    void
1391    cache::collect_object_files ()
1392    {
1393      for (path::paths::iterator ni = paths_.begin (); ni != paths_.end (); ++ni)
1394        collect_object_files (*ni);
1395    }
1396
1397    void
1398    cache::collect_object_files (const std::string& path)
1399    {
1400      archive* ar = new archive (path);
1401
1402      if (ar->is_valid ())
1403      {
1404        try
1405        {
1406          ar->open ();
1407          ar->load_objects (objects_);
1408          ar->close ();
1409          archives_[path] = ar;
1410        }
1411        catch (...)
1412        {
1413          delete ar;
1414          throw;
1415        }
1416      }
1417      else
1418      {
1419        delete ar;
1420        object* obj = new object (path);
1421        if (!obj->name ().exists ())
1422        {
1423          delete obj;
1424          throw rld::error ("'" + path + "', Not found or a regular file.",
1425                            "file-check");
1426        }
1427        try
1428        {
1429          obj->open ();
1430          obj->begin ();
1431          obj->end ();
1432          obj->close ();
1433          objects_[path] = obj;
1434        }
1435        catch (...)
1436        {
1437          delete obj;
1438          throw;
1439        }
1440      }
1441    }
1442
1443    void
1444    cache::load_symbols (rld::symbols::table& symbols, bool local)
1445    {
1446      if (rld::verbose () >= RLD_VERBOSE_INFO)
1447        std::cout << "cache:load-sym: object files: " << objects_.size ()
1448                  << std::endl;
1449
1450      for (objects::iterator oi = objects_.begin ();
1451           oi != objects_.end ();
1452           ++oi)
1453      {
1454        object* obj = (*oi).second;
1455        obj->open ();
1456        obj->begin ();
1457        obj->load_symbols (symbols, local);
1458        obj->end ();
1459        obj->close ();
1460      }
1461
1462      if (rld::verbose () >= RLD_VERBOSE_INFO)
1463        std::cout << "cache:load-sym: symbols: " << symbols.size ()
1464                  << std::endl;
1465    }
1466
1467    void
1468    cache::output_unresolved_symbols (std::ostream& out)
1469    {
1470      for (objects::iterator oi = objects_.begin ();
1471           oi != objects_.end ();
1472           ++oi)
1473      {
1474        object* obj = (*oi).second;
1475        if (obj)
1476        {
1477          out << obj->name ().full () << ':' << std::endl;
1478          rld::symbols::output (out, obj->unresolved_symbols ());
1479        }
1480      }
1481    }
1482
1483    archives&
1484    cache::get_archives ()
1485    {
1486      return archives_;
1487    }
1488
1489    objects&
1490    cache::get_objects ()
1491    {
1492      return objects_;
1493    }
1494
1495    void
1496    cache::get_objects (object_list& list) const
1497    {
1498      list.clear ();
1499      for (path::paths::const_iterator pi = paths_.begin ();
1500           pi != paths_.end ();
1501           ++pi)
1502      {
1503        objects::const_iterator oi = objects_.find (*pi);
1504        if (oi == objects_.end ())
1505          throw rld::error ("Not located or a valid format", *pi);
1506        list.push_back ((*oi).second);
1507      }
1508    }
1509
1510    const path::paths&
1511    cache::get_paths () const
1512    {
1513      return paths_;
1514    }
1515
1516    int
1517    cache::archive_count () const
1518    {
1519      return archives_.size ();
1520    }
1521
1522    int
1523    cache::object_count () const
1524    {
1525      return objects_.size ();
1526    }
1527
1528    int
1529    cache::path_count () const
1530    {
1531      return paths_.size ();
1532    }
1533
1534    void
1535    cache::get_archive_files (files& afiles)
1536    {
1537      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1538        afiles.push_back ((*ai).second->name ().full ());
1539    }
1540
1541    void
1542    cache::get_object_files (files& ofiles)
1543    {
1544      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1545        ofiles.push_back ((*oi).second->name ());
1546    }
1547
1548    void
1549    cache::output_archive_files (std::ostream& out)
1550    {
1551      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1552        out << ' ' << (*ai).second->name ().full () << std::endl;
1553    }
1554
1555    void
1556    cache::output_object_files (std::ostream& out)
1557    {
1558      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1559        out << ' ' << (*oi).second->name ().full () << std::endl;
1560    }
1561
1562    void
1563    cache::input (const std::string& path)
1564    {
1565      if (opened)
1566      {
1567        collect_object_files (path);
1568        archive_begin (path);
1569      }
1570    }
1571
1572    void
1573    find_libraries (path::paths& libraries,
1574                    path::paths& libpaths,
1575                    path::paths& libs)
1576    {
1577      if (rld::verbose () >= RLD_VERBOSE_INFO)
1578        std::cout << "Finding libraries:" << std::endl;
1579      libraries.clear ();
1580      for (path::paths::size_type l = 0; l < libs.size (); ++l)
1581      {
1582        std::string lib = "lib" + libs[l] + ".a";
1583        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
1584          std::cout << " searching: " << lib << std::endl;
1585        bool found = false;
1586        for (path::paths::size_type p = 0; p < libpaths.size (); ++p)
1587        {
1588          std::string plib;
1589          path::path_join (libpaths[p], lib, plib);
1590          if (rld::verbose () >= RLD_VERBOSE_DETAILS)
1591              std::cout << " checking: " << plib << std::endl;
1592          if (path::check_file (plib))
1593          {
1594            if (rld::verbose () >= RLD_VERBOSE_INFO)
1595              std::cout << " found: " << plib << std::endl;
1596            libraries.push_back (plib);
1597            found = true;
1598            break;
1599          }
1600        }
1601
1602        if (!found)
1603          throw rld::error ("Not found", lib);
1604      }
1605    }
1606
1607  }
1608}
Note: See TracBrowser for help on using the repository browser.