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

5
Last change on this file since fa81491 was 8e64821, checked in by Chris Johns <chrisj@…>, on 09/14/17 at 02:21:08

rtemstoolkit: Remove throw from file::image destructor.

  • Property mode set to 100644
File size: 38.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        std::cerr << "rtl:file:image: references when destructing";
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    byteorder
410    image::get_byteorder () const
411    {
412      switch (elf_.data_type ())
413      {
414        case ELFDATA2LSB:
415          return little_endian;
416        case ELFDATA2MSB:
417          return big_endian;
418      }
419      throw rld::error ("invalid elf data type", "byteorder: " + name ().path ());
420    }
421
422    void
423    image::symbol_referenced ()
424    {
425      ++symbol_refs;
426    }
427
428    int
429    image::symbol_references () const
430    {
431      return symbol_refs;
432    }
433
434    void
435    copy_file (image& in, image& out, size_t size)
436    {
437      #define COPY_FILE_BUFFER_SIZE (8 * 1024)
438      uint8_t* buffer = 0;
439
440      if (size == 0)
441        size = in.name ().size ();
442
443      try
444      {
445        buffer = new uint8_t[COPY_FILE_BUFFER_SIZE];
446        while (size)
447        {
448          /*
449           * @fixme the reading and writing are not POSIX; sigints could split them.
450           */
451
452          size_t l = size < COPY_FILE_BUFFER_SIZE ? size : COPY_FILE_BUFFER_SIZE;
453          ssize_t r = ::read (in.fd (), buffer, l);
454
455          if (r < 0)
456            throw rld::error (::strerror (errno), "reading: " + in.name ().full ());
457
458          if (r == 0)
459          {
460            std::ostringstream oss;
461            oss << "reading: " + in.name ().full () << " (" << size << ')';
462            throw rld::error ("input too short", oss.str ());
463          }
464
465          ssize_t w = ::write (out.fd (), buffer, r);
466
467          if (w < 0)
468            throw rld::error (::strerror (errno), "writing: " + out.name ().full ());
469
470          if (w != r)
471            throw rld::error ("output trucated", "writing: " + out.name ().full ());
472
473          size -= r;
474        }
475      }
476      catch (...)
477      {
478        delete [] buffer;
479        throw;
480      }
481
482      if (buffer)
483        delete [] buffer;
484    }
485
486    /**
487     * Defines for the header of an archive.
488     */
489    #define rld_archive_ident         "!<arch>\n"
490    #define rld_archive_ident_size    (sizeof (rld_archive_ident) - 1)
491    #define rld_archive_fhdr_base     rld_archive_ident_size
492    #define rld_archive_fname         (0)
493    #define rld_archive_fname_size    (16)
494    #define rld_archive_mtime         (16)
495    #define rld_archive_mtime_size    (12)
496    #define rld_archive_uid           (28)
497    #define rld_archive_uid_size      (6)
498    #define rld_archive_gid           (34)
499    #define rld_archive_gid_size      (6)
500    #define rld_archive_mode          (40)
501    #define rld_archive_mode_size     (8)
502    #define rld_archive_size          (48)
503    #define rld_archive_size_size     (10)
504    #define rld_archive_magic         (58)
505    #define rld_archive_magic_size    (2)
506    #define rld_archive_fhdr_size     (60)
507    #define rld_archive_max_file_size (1024)
508
509    archive::archive (const std::string& path)
510      : image (path, false)
511    {
512      if (!name ().is_valid ())
513        throw rld_error_at ("name is empty");
514      if (!name ().is_archive ())
515        throw rld_error_at ("name is not an archive: " + name ().oname ());
516    }
517
518    archive::~archive ()
519    {
520      end ();
521      close ();
522    }
523
524    void
525    archive::begin ()
526    {
527      if (references () == 1)
528      {
529        elf ().begin (name ().full (), fd ());
530
531        /*
532         * Make sure it is an archive.
533         */
534        if (!elf ().is_archive ())
535          throw rld::error ("Not an archive.",
536                            "archive-begin:" + name ().full ());
537      }
538    }
539
540    void
541    archive::end ()
542    {
543      if (references () == 1)
544        elf ().end ();
545    }
546
547    bool
548    archive::is (const std::string& path) const
549    {
550      return name ().path () == path;
551    }
552
553    bool
554    archive::is_valid ()
555    {
556      open ();
557      uint8_t header[rld_archive_ident_size];
558      seek_read (0, &header[0], rld_archive_ident_size);
559      bool result = ::memcmp (header, rld_archive_ident,
560                              rld_archive_ident_size) == 0 ? true : false;
561      close ();
562      return result;
563    }
564
565    void
566    archive::load_objects (objects& objs)
567    {
568      off_t extended_file_names = 0;
569      off_t offset = rld_archive_fhdr_base;
570      size_t size = 0;
571
572      while (true)
573      {
574        uint8_t header[rld_archive_fhdr_size];
575
576        if (!read_header (offset, &header[0]))
577          break;
578
579        /*
580         * The archive file headers are always aligned to an even address.
581         */
582        size =
583          (scan_decimal (&header[rld_archive_size],
584                         rld_archive_size_size) + 1) & ~1;
585
586        /*
587         * Check for the GNU extensions.
588         */
589        if (header[0] == '/')
590        {
591          off_t extended_off;
592
593          switch (header[1])
594          {
595            case ' ':
596              /*
597               * Symbols table. Ignore the table.
598               */
599              break;
600            case '/':
601              /*
602               * Extended file names table. Remember.
603               */
604              extended_file_names = offset + rld_archive_fhdr_size;
605              break;
606            case '0':
607            case '1':
608            case '2':
609            case '3':
610            case '4':
611            case '5':
612            case '6':
613            case '7':
614            case '8':
615            case '9':
616              /*
617               * Offset into the extended file name table. If we do not have the
618               * offset to the extended file name table find it.
619               */
620              extended_off = scan_decimal (&header[1], rld_archive_fname_size);
621
622              if (extended_file_names == 0)
623              {
624                off_t off = offset;
625                while (extended_file_names == 0)
626                {
627                  size_t esize =
628                    (scan_decimal (&header[rld_archive_size],
629                                   rld_archive_size_size) + 1) & ~1;
630                  off += esize + rld_archive_fhdr_size;
631
632                  if (!read_header (off, &header[0]))
633                    throw rld::error ("No GNU extended file name section found",
634                                      "get-names:" + name ().path ());
635
636                  if ((header[0] == '/') && (header[1] == '/'))
637                  {
638                    extended_file_names = off + rld_archive_fhdr_size;
639                    break;
640                  }
641                }
642              }
643
644              if (extended_file_names)
645              {
646                /*
647                 * We know the offset in the archive to the extended file. Read
648                 * the name from the table and compare with the name we are
649                 * after.
650                 */
651                char cname[rld_archive_max_file_size];
652                seek_read (extended_file_names + extended_off,
653                           (uint8_t*) &cname[0], rld_archive_max_file_size);
654                add_object (objs, cname,
655                            offset + rld_archive_fhdr_size, size);
656              }
657              break;
658            default:
659              /*
660               * Ignore the file because we do not know what it it.
661               */
662              break;
663          }
664        }
665        else
666        {
667          /*
668           * Normal archive name.
669           */
670          add_object (objs,
671                      (char*) &header[rld_archive_fname],
672                      offset + rld_archive_fhdr_size, size);
673        }
674
675        offset += size + rld_archive_fhdr_size;
676      }
677    }
678
679    bool
680    archive::operator< (const archive& rhs) const
681    {
682      return name ().path () < rhs.name ().path ();
683    }
684
685    bool
686    archive::read_header (off_t offset, uint8_t* header)
687    {
688      if (!seek_read (offset, header, rld_archive_fhdr_size))
689        return false;
690
691      if ((header[rld_archive_magic] != 0x60) ||
692          (header[rld_archive_magic + 1] != 0x0a))
693        throw rld::error ("Invalid header magic numbers at " +
694                          rld::to_string (offset), "read-header:" + name ().path ());
695
696      return true;
697    }
698
699    void
700    archive::add_object (objects& objs, const char* path, off_t offset, size_t size)
701    {
702      const char* end = path;
703      while ((*end != '\0') && (*end != '/') && (*end != '\n'))
704        ++end;
705
706      std::string str;
707      str.append (path, end - path);
708
709      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
710        std::cout << "archive::add-object: " << str << std::endl;
711
712      file n (name ().path (), str, offset, size);
713      objs[n.full()] = new object (*this, n);
714    }
715
716    void
717    archive::write_header (const std::string& name,
718                           uint32_t           mtime,
719                           int                uid,
720                           int                gid,
721                           int                mode,
722                           size_t             size)
723    {
724        uint8_t header[rld_archive_fhdr_size];
725
726        memset (header, ' ', sizeof (header));
727
728        size_t len = name.length ();
729        if (len > rld_archive_fname_size)
730          len = rld_archive_fname_size;
731        memcpy (&header[rld_archive_fname], &name[0], len);
732
733        set_number (mtime, header + rld_archive_mtime, rld_archive_mtime_size);
734        set_number (uid, header + rld_archive_uid, rld_archive_uid_size);
735        set_number (gid, header + rld_archive_gid, rld_archive_gid_size);
736        set_number (mode, header + rld_archive_mode, rld_archive_mode_size, true);
737        set_number (size, header + rld_archive_size, rld_archive_size_size);
738
739        header[rld_archive_magic] = 0x60;
740        header[rld_archive_magic + 1] = 0x0a;
741
742        write (header, sizeof (header));
743    }
744
745    void
746    archive::create (object_list& objects)
747    {
748      if (rld::verbose () >= RLD_VERBOSE_DETAILS)
749        std::cout << "archive::create: " << name ().full ()
750                  << ", objects: " << objects.size () << std::endl;
751
752      open (true);
753
754      try
755      {
756        seek_write (0, rld_archive_ident, rld_archive_ident_size);
757
758        /*
759         * GNU extended filenames.
760         */
761        std::string extended_file_names;
762
763        for (object_list::iterator oi = objects.begin ();
764             oi != objects.end ();
765             ++oi)
766        {
767          object& obj = *(*oi);
768          const std::string&  oname = path::basename (obj.name ().oname ());
769          if (oname.length () >= rld_archive_fname_size)
770            extended_file_names += oname + '\n';
771        }
772
773        if (!extended_file_names.empty ())
774        {
775          if (extended_file_names.length () & 1)
776          {
777            extended_file_names += ' ';
778          }
779          write_header ("//", 0, 0, 0, 0, extended_file_names.length ());
780          write (extended_file_names.c_str (), extended_file_names.length ());
781        }
782
783        for (object_list::iterator oi = objects.begin ();
784             oi != objects.end ();
785             ++oi)
786        {
787          object& obj = *(*oi);
788
789          obj.open ();
790
791          try
792          {
793            std::string oname = path::basename (obj.name ().oname ());
794
795            /*
796             * Convert the file name to an offset into the extended file name
797             * table if the file name is too long for the header.
798             */
799
800            if (oname.length () >= rld_archive_fname_size)
801            {
802              size_t pos = extended_file_names.find (oname + '\n');
803              if (pos == std::string::npos)
804                throw rld_error_at ("extended file name not found");
805              std::ostringstream oss;
806              oss << '/' << pos;
807              oname = oss.str ();
808            }
809            else oname += '/';
810
811            write_header (oname, 0, 0, 0, 0666, (obj.name ().size () + 1) & ~1);
812            obj.seek (0);
813            copy_file (obj, *this);
814            if (obj.name ().size () & 1)
815              write ("\n", 1);
816          }
817          catch (...)
818          {
819            obj.close ();
820            throw;
821          }
822
823          obj.close ();
824        }
825      }
826      catch (...)
827      {
828        close ();
829        throw;
830      }
831
832      close ();
833    }
834
835    relocation::relocation (const elf::relocation& er)
836      : offset (er.offset ()),
837        type (er.type ()),
838        info (er.info ()),
839        addend (er.addend ()),
840        symname (er.symbol ().name ()),
841        symtype (er.symbol ().type ()),
842        symsect (er.symbol ().section_index ()),
843        symvalue (er.symbol ().value ()),
844        symbinding (er.symbol ().binding ())
845    {
846    }
847
848    section::section (const elf::section& es)
849      : name (es.name ()),
850        index (es.index ()),
851        type (es.type ()),
852        size (es.size ()),
853        alignment (es.alignment ()),
854        link (es.link ()),
855        info (es.info ()),
856        flags (es.flags ()),
857        offset (es.offset ()),
858        address (es.address ()),
859        rela (es.get_reloc_type ())
860    {
861    }
862
863    void
864    section::load_relocations (const elf::section& es)
865    {
866      const elf::relocations& es_relocs = es.get_relocations ();
867      for (elf::relocations::const_iterator ri = es_relocs.begin ();
868           ri != es_relocs.end ();
869           ++ri)
870      {
871        relocs.push_back (relocation (*ri));
872      }
873      rela = es.get_reloc_type ();
874    }
875
876    size_t
877    sum_sizes (const sections& secs)
878    {
879      size_t size = 0;
880
881      for (sections::const_iterator si = secs.begin ();
882           si != secs.end ();
883           ++si)
884      {
885        const section& sec = *si;
886
887        if ((size % sec.alignment) != 0)
888          size -= (size % sec.alignment) + sec.alignment;
889        size += sec.size;
890      }
891
892      return size;
893    }
894
895    const section*
896    find (const sections& secs, const int index)
897    {
898      for (sections::const_iterator si = secs.begin ();
899           si != secs.end ();
900           ++si)
901      {
902        const section& sec = *si;
903
904        if (index == sec.index)
905          return &sec;
906      }
907
908      return 0;
909    }
910
911    object::object (archive& archive_, file& name_)
912      : image (name_),
913        archive_ (&archive_),
914        valid_ (false),
915        resolving_ (false),
916        resolved_ (false)
917    {
918      if (!name ().is_valid ())
919        throw rld_error_at ("name is empty");
920    }
921
922    object::object (const std::string& path)
923      : image (path),
924        archive_ (0),
925        valid_ (false),
926        resolving_ (false),
927        resolved_ (false)
928    {
929      if (!name ().is_valid ())
930        throw rld_error_at ("name is empty");
931    }
932
933    object::object ()
934      : archive_ (0),
935        valid_ (false),
936        resolving_ (false),
937        resolved_ (false)
938    {
939    }
940
941    object::~object ()
942    {
943      end ();
944      close ();
945    }
946
947    void
948    object::open (bool writable)
949    {
950      if (archive_)
951      {
952        if (writable)
953          throw rld_error_at ("object files in archives are not writable");
954        archive_->open ();
955      }
956      else
957        image::open (writable);
958    }
959
960    void
961    object::close ()
962    {
963      if (archive_)
964      {
965        archive_->end ();
966        archive_->close ();
967      }
968      else
969      {
970        end ();
971        image::close ();
972      }
973    }
974
975    void
976    object::begin ()
977    {
978      /*
979       * Begin a session.
980       */
981
982      if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
983        std::cout << "object:begin: " << name ().full () << " in-archive:"
984                  << ((char*) (archive_ ? "yes" : "no")) << std::endl;
985
986      if (archive_)
987        elf ().begin (name ().full (), archive_->elf(), name ().offset ());
988      else
989        elf ().begin (name ().full (), fd (), is_writable ());
990
991      /*
992       * Cannot be an archive.
993       */
994      if (elf ().is_archive ())
995        throw rld::error ("Is an archive not an object file.",
996                          "object-begin:" + name ().full ());
997
998      /*
999       * We only support executable or relocatable ELF files.
1000       */
1001      if (!is_writable ())
1002      {
1003        if (!elf ().is_executable () && !elf ().is_relocatable ())
1004          throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).",
1005                            "object-begin:" + name ().full ());
1006
1007        elf::check_file (elf ());
1008
1009        /**
1010         * We assume the ELF file is invariant over the linking process.
1011         */
1012
1013        if (secs.empty ())
1014        {
1015          elf::sections elf_secs;
1016
1017          elf ().get_sections (elf_secs, 0);
1018
1019          for (elf::sections::const_iterator esi = elf_secs.begin ();
1020               esi != elf_secs.end ();
1021               ++esi)
1022          {
1023            secs.push_back (section (*(*esi)));
1024          }
1025        }
1026      }
1027
1028      /*
1029       * This is a valid object file. The file format checks out.
1030       */
1031      valid_ = true;
1032    }
1033
1034    void
1035    object::end ()
1036    {
1037      if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
1038        std::cout << "object:end: " << name ().full () << std::endl;
1039
1040      elf ().end ();
1041    }
1042
1043    bool
1044    object::valid () const
1045    {
1046      return valid_;
1047    }
1048
1049    void
1050    object::load_symbols (rld::symbols::table& symbols, bool local)
1051    {
1052      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1053        std::cout << "object:load-sym: " << name ().full () << std::endl;
1054
1055      rld::symbols::pointers syms;
1056
1057      if (local)
1058      {
1059        elf ().get_symbols (syms, false, true, false, false);
1060
1061        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1062          std::cout << "object:load-sym: local: total "
1063                    << syms.size () << std::endl;
1064
1065        for (symbols::pointers::iterator si = syms.begin ();
1066             si != syms.end ();
1067             ++si)
1068        {
1069          symbols::symbol& sym = *(*si);
1070
1071          if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1072            std::cout << "object:load-sym: local: " << sym << std::endl;
1073
1074          sym.set_object (*this);
1075          symbols.add_local (sym);
1076        }
1077      }
1078
1079      elf ().get_symbols (syms, false, false, true, false);
1080
1081      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1082        std::cout << "object:load-sym: weak: total "
1083                  << syms.size () << std::endl;
1084
1085      for (symbols::pointers::iterator si = syms.begin ();
1086           si != syms.end ();
1087           ++si)
1088      {
1089        symbols::symbol& sym = *(*si);
1090
1091        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1092          std::cout << "object:load-sym: weak: " << sym << std::endl;
1093
1094        sym.set_object (*this);
1095        symbols.add_weak (sym);
1096        externals.push_back (&sym);
1097      }
1098
1099      elf ().get_symbols (syms, false, false, false, true);
1100
1101      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1102        std::cout << "object:load-sym: global: total "
1103                  << syms.size () << std::endl;
1104
1105      for (symbols::pointers::iterator si = syms.begin ();
1106           si != syms.end ();
1107           ++si)
1108      {
1109        symbols::symbol& sym = *(*si);
1110
1111        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1112          std::cout << "object:load-sym: global: " << sym << std::endl;
1113
1114        sym.set_object (*this);
1115        symbols.add_global (sym);
1116        externals.push_back (&sym);
1117      }
1118
1119      elf ().get_symbols (syms, true, false, true, true);
1120
1121      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1122        std::cout << "object:load-sym: unresolved: 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: unresolved: ";
1134          sym.output (std::cout);
1135          std::cout << std::endl;
1136        }
1137
1138        unresolved[sym.name ()] = &sym;
1139      }
1140    }
1141
1142    void
1143    object::load_relocations ()
1144    {
1145      if (rld::verbose () >= RLD_VERBOSE_TRACE)
1146        std::cout << "object:load-relocs: " << name ().full () << std::endl;
1147
1148      elf ().load_relocations ();
1149
1150      for (sections::iterator si = secs.begin ();
1151           si != secs.end ();
1152           ++si)
1153      {
1154        section&            sec = *si;
1155        const elf::section& elf_sec = elf ().get_section (sec.index);
1156        sec.load_relocations (elf_sec);
1157      }
1158    }
1159
1160    int
1161    object::references () const
1162    {
1163      if (archive_)
1164        return archive_->references ();
1165      return image::references ();
1166    }
1167
1168    size_t
1169    object::size () const
1170    {
1171      if (archive_)
1172        return archive_->size ();
1173      return image::size ();
1174    }
1175
1176    int
1177    object::fd () const
1178    {
1179      if (archive_)
1180        return archive_->fd ();
1181      return image::fd ();
1182    }
1183
1184    void
1185    object::symbol_referenced ()
1186    {
1187      image::symbol_referenced ();
1188      if (archive_)
1189        archive_->symbol_referenced ();
1190    }
1191
1192    archive*
1193    object::get_archive ()
1194    {
1195      return archive_;
1196    }
1197
1198    rld::symbols::symtab&
1199    object::unresolved_symbols ()
1200    {
1201      return unresolved;
1202    }
1203
1204    rld::symbols::pointers&
1205    object::external_symbols ()
1206    {
1207      return externals;
1208    }
1209
1210    void
1211    object::get_sections (sections& filtered_secs,
1212                          uint32_t  type,
1213                          uint64_t  flags_in,
1214                          uint64_t  flags_out)
1215    {
1216      for (sections::const_iterator si = secs.begin ();
1217           si != secs.end ();
1218           ++si)
1219      {
1220        const section& sec = *si;
1221        if ((type == 0) || (type == sec.type))
1222        {
1223          if ((flags_in == 0) ||
1224              (((sec.flags & flags_in) == flags_in) &&
1225               ((sec.flags & flags_out) == 0)))
1226          {
1227            filtered_secs.push_back (sec);
1228          }
1229        }
1230      }
1231    }
1232
1233    void
1234    object::get_sections (sections& filtered_secs, const std::string& matching_name)
1235    {
1236      for (sections::const_iterator si = secs.begin ();
1237           si != secs.end ();
1238           ++si)
1239      {
1240        const section& sec = *si;
1241        if (sec.name == matching_name)
1242        {
1243          filtered_secs.push_back (sec);
1244        }
1245      }
1246    }
1247
1248    const section&
1249    object::get_section (int index) const
1250    {
1251      for (sections::const_iterator si = secs.begin ();
1252           si != secs.end ();
1253           ++si)
1254      {
1255        const section& sec = *si;
1256        if (sec.index == index)
1257          return sec;
1258      }
1259
1260      throw rld::error ("Section index '" + rld::to_string (index) +
1261                        "' not found: " + name ().full (), "object::get-section");
1262    }
1263
1264    void
1265    object::resolve_set ()
1266    {
1267      resolving_ = true;
1268    }
1269
1270    void
1271    object::resolve_clear ()
1272    {
1273      resolving_ = false;
1274    }
1275
1276    bool
1277    object::resolving () const
1278    {
1279      return resolving_;
1280    }
1281
1282    void
1283    object::resolved_set ()
1284    {
1285      resolved_ = true;
1286    }
1287
1288    bool
1289    object::resolved () const
1290    {
1291      return resolved_;
1292    }
1293
1294    cache::cache ()
1295      : opened (false)
1296    {
1297    }
1298
1299    cache::~cache ()
1300    {
1301      close ();
1302    }
1303
1304    void
1305    cache::open ()
1306    {
1307      if (!opened)
1308      {
1309        collect_object_files ();
1310        archives_begin ();
1311        opened = true;
1312      }
1313    }
1314
1315    void
1316    cache::close ()
1317    {
1318      if (opened)
1319      {
1320        /*
1321         * Must delete the object first as they could depend on archives.
1322         */
1323        for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1324          delete (*oi).second;
1325        for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1326          delete (*ai).second;
1327        opened = false;
1328      }
1329    }
1330
1331    void
1332    cache::add (const std::string& path)
1333    {
1334        paths_.push_back (path);
1335        input (path);
1336    }
1337
1338    void
1339    cache::add (path::paths& paths__)
1340    {
1341      for (path::paths::iterator pi = paths__.begin();
1342           pi != paths__.end();
1343           ++pi)
1344        add (*pi);
1345    }
1346
1347    void
1348    cache::add_libraries (path::paths& paths__)
1349    {
1350      for (path::paths::iterator pi = paths__.begin();
1351           pi != paths__.end();
1352           ++pi)
1353        input (*pi);
1354    }
1355
1356    void
1357    cache::archive_begin (const std::string& path)
1358    {
1359      archives::iterator ai = archives_.find (path);
1360      if (ai != archives_.end ())
1361      {
1362        archive* ar = (*ai).second;
1363        if (!ar->is_open ())
1364        {
1365          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1366            std::cout << "cache:archive-begin: " << path << std::endl;
1367          ar->open ();
1368          ar->begin ();
1369        }
1370      }
1371    }
1372
1373    void
1374    cache::archive_end (const std::string& path)
1375    {
1376      archives::iterator ai = archives_.find (path);
1377      if (ai != archives_.end ())
1378      {
1379        archive* ar = (*ai).second;
1380        if (ar->is_open ())
1381        {
1382          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1383            std::cout << "cache:archive-end: " << path << std::endl;
1384          ar->end ();
1385          ar->close ();
1386        }
1387      }
1388    }
1389
1390    void
1391    cache::archives_begin ()
1392    {
1393      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1394        archive_begin (((*ai).second)->path ());
1395    }
1396
1397    void
1398    cache::archives_end ()
1399    {
1400      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1401        archive_end (((*ai).second)->path ());
1402    }
1403
1404    void
1405    cache::collect_object_files ()
1406    {
1407      for (path::paths::iterator ni = paths_.begin (); ni != paths_.end (); ++ni)
1408        collect_object_files (*ni);
1409    }
1410
1411    void
1412    cache::collect_object_files (const std::string& path)
1413    {
1414      archive* ar = new archive (path);
1415
1416      if (ar->is_valid ())
1417      {
1418        try
1419        {
1420          ar->open ();
1421          ar->load_objects (objects_);
1422          ar->close ();
1423          archives_[path] = ar;
1424        }
1425        catch (...)
1426        {
1427          delete ar;
1428          throw;
1429        }
1430      }
1431      else
1432      {
1433        delete ar;
1434        object* obj = new object (path);
1435        if (!obj->name ().exists ())
1436        {
1437          delete obj;
1438          throw rld::error ("'" + path + "', Not found or a regular file.",
1439                            "file-check");
1440        }
1441        try
1442        {
1443          obj->open ();
1444          obj->begin ();
1445          obj->end ();
1446          obj->close ();
1447          objects_[path] = obj;
1448        }
1449        catch (...)
1450        {
1451          delete obj;
1452          throw;
1453        }
1454      }
1455    }
1456
1457    void
1458    cache::load_symbols (rld::symbols::table& symbols, bool local)
1459    {
1460      if (rld::verbose () >= RLD_VERBOSE_INFO)
1461        std::cout << "cache:load-sym: object files: " << objects_.size ()
1462                  << std::endl;
1463
1464      for (objects::iterator oi = objects_.begin ();
1465           oi != objects_.end ();
1466           ++oi)
1467      {
1468        object* obj = (*oi).second;
1469        obj->open ();
1470        obj->begin ();
1471        obj->load_symbols (symbols, local);
1472        obj->end ();
1473        obj->close ();
1474      }
1475
1476      if (rld::verbose () >= RLD_VERBOSE_INFO)
1477        std::cout << "cache:load-sym: symbols: " << symbols.size ()
1478                  << std::endl;
1479    }
1480
1481    void
1482    cache::output_unresolved_symbols (std::ostream& out)
1483    {
1484      for (objects::iterator oi = objects_.begin ();
1485           oi != objects_.end ();
1486           ++oi)
1487      {
1488        object* obj = (*oi).second;
1489        if (obj)
1490        {
1491          out << obj->name ().full () << ':' << std::endl;
1492          rld::symbols::output (out, obj->unresolved_symbols ());
1493        }
1494      }
1495    }
1496
1497    archives&
1498    cache::get_archives ()
1499    {
1500      return archives_;
1501    }
1502
1503    objects&
1504    cache::get_objects ()
1505    {
1506      return objects_;
1507    }
1508
1509    void
1510    cache::get_objects (object_list& list) const
1511    {
1512      list.clear ();
1513      for (path::paths::const_iterator pi = paths_.begin ();
1514           pi != paths_.end ();
1515           ++pi)
1516      {
1517        objects::const_iterator oi = objects_.find (*pi);
1518        if (oi == objects_.end ())
1519          throw rld::error ("Not located or a valid format", *pi);
1520        list.push_back ((*oi).second);
1521      }
1522    }
1523
1524    const path::paths&
1525    cache::get_paths () const
1526    {
1527      return paths_;
1528    }
1529
1530    int
1531    cache::archive_count () const
1532    {
1533      return archives_.size ();
1534    }
1535
1536    int
1537    cache::object_count () const
1538    {
1539      return objects_.size ();
1540    }
1541
1542    int
1543    cache::path_count () const
1544    {
1545      return paths_.size ();
1546    }
1547
1548    void
1549    cache::get_archive_files (files& afiles)
1550    {
1551      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1552        afiles.push_back ((*ai).second->name ().full ());
1553    }
1554
1555    void
1556    cache::get_object_files (files& ofiles)
1557    {
1558      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1559        ofiles.push_back ((*oi).second->name ());
1560    }
1561
1562    void
1563    cache::output_archive_files (std::ostream& out)
1564    {
1565      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1566        out << ' ' << (*ai).second->name ().full () << std::endl;
1567    }
1568
1569    void
1570    cache::output_object_files (std::ostream& out)
1571    {
1572      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1573        out << ' ' << (*oi).second->name ().full () << std::endl;
1574    }
1575
1576    void
1577    cache::input (const std::string& path)
1578    {
1579      if (opened)
1580      {
1581        collect_object_files (path);
1582        archive_begin (path);
1583      }
1584    }
1585
1586    void
1587    find_libraries (path::paths& libraries,
1588                    path::paths& libpaths,
1589                    path::paths& libs)
1590    {
1591      if (rld::verbose () >= RLD_VERBOSE_INFO)
1592        std::cout << "Finding libraries:" << std::endl;
1593      libraries.clear ();
1594      for (path::paths::size_type l = 0; l < libs.size (); ++l)
1595      {
1596        std::string lib = "lib" + libs[l] + ".a";
1597        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
1598          std::cout << " searching: " << lib << std::endl;
1599        bool found = false;
1600        for (path::paths::size_type p = 0; p < libpaths.size (); ++p)
1601        {
1602          std::string plib;
1603          path::path_join (libpaths[p], lib, plib);
1604          if (rld::verbose () >= RLD_VERBOSE_DETAILS)
1605              std::cout << " checking: " << plib << std::endl;
1606          if (path::check_file (plib))
1607          {
1608            if (rld::verbose () >= RLD_VERBOSE_INFO)
1609              std::cout << " found: " << plib << std::endl;
1610            libraries.push_back (plib);
1611            found = true;
1612            break;
1613          }
1614        }
1615
1616        if (!found)
1617          throw rld::error ("Not found", lib);
1618      }
1619    }
1620
1621  }
1622}
Note: See TracBrowser for help on using the repository browser.