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

5
Last change on this file since 7d3350d was 8dc2772, checked in by Chris Johns <chrisj@…>, on 04/03/16 at 05:39:58

rtemstoolkit: Add the address to the section.

  • 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        address (es.address ()),
846        rela (es.get_reloc_type ())
847    {
848    }
849
850    void
851    section::load_relocations (const elf::section& es)
852    {
853      const elf::relocations& es_relocs = es.get_relocations ();
854      for (elf::relocations::const_iterator ri = es_relocs.begin ();
855           ri != es_relocs.end ();
856           ++ri)
857      {
858        relocs.push_back (relocation (*ri));
859      }
860      rela = es.get_reloc_type ();
861    }
862
863    size_t
864    sum_sizes (const sections& secs)
865    {
866      size_t size = 0;
867
868      for (sections::const_iterator si = secs.begin ();
869           si != secs.end ();
870           ++si)
871      {
872        const section& sec = *si;
873
874        if ((size % sec.alignment) != 0)
875          size -= (size % sec.alignment) + sec.alignment;
876        size += sec.size;
877      }
878
879      return size;
880    }
881
882    const section*
883    find (const sections& secs, const int index)
884    {
885      for (sections::const_iterator si = secs.begin ();
886           si != secs.end ();
887           ++si)
888      {
889        const section& sec = *si;
890
891        if (index == sec.index)
892          return &sec;
893      }
894
895      return 0;
896    }
897
898    object::object (archive& archive_, file& name_)
899      : image (name_),
900        archive_ (&archive_),
901        valid_ (false),
902        resolving_ (false),
903        resolved_ (false)
904    {
905      if (!name ().is_valid ())
906        throw rld_error_at ("name is empty");
907    }
908
909    object::object (const std::string& path)
910      : image (path),
911        archive_ (0),
912        valid_ (false),
913        resolving_ (false),
914        resolved_ (false)
915    {
916      if (!name ().is_valid ())
917        throw rld_error_at ("name is empty");
918    }
919
920    object::object ()
921      : archive_ (0),
922        valid_ (false),
923        resolving_ (false),
924        resolved_ (false)
925    {
926    }
927
928    object::~object ()
929    {
930      end ();
931      close ();
932    }
933
934    void
935    object::open (bool writable)
936    {
937      if (archive_)
938      {
939        if (writable)
940          throw rld_error_at ("object files in archives are not writable");
941        archive_->open ();
942      }
943      else
944        image::open (writable);
945    }
946
947    void
948    object::close ()
949    {
950      if (archive_)
951      {
952        archive_->end ();
953        archive_->close ();
954      }
955      else
956      {
957        end ();
958        image::close ();
959      }
960    }
961
962    void
963    object::begin ()
964    {
965      /*
966       * Begin a session.
967       */
968
969      if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
970        std::cout << "object:begin: " << name ().full () << " in-archive:"
971                  << ((char*) (archive_ ? "yes" : "no")) << std::endl;
972
973      if (archive_)
974        elf ().begin (name ().full (), archive_->elf(), name ().offset ());
975      else
976        elf ().begin (name ().full (), fd (), is_writable ());
977
978      /*
979       * Cannot be an archive.
980       */
981      if (elf ().is_archive ())
982        throw rld::error ("Is an archive not an object file.",
983                          "object-begin:" + name ().full ());
984
985      /*
986       * We only support executable or relocatable ELF files.
987       */
988      if (!is_writable ())
989      {
990        if (!elf ().is_executable () && !elf ().is_relocatable ())
991          throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).",
992                            "object-begin:" + name ().full ());
993
994        elf::check_file (elf ());
995
996        /**
997         * We assume the ELF file is invariant over the linking process.
998         */
999
1000        if (secs.empty ())
1001        {
1002          elf::sections elf_secs;
1003
1004          elf ().get_sections (elf_secs, 0);
1005
1006          for (elf::sections::const_iterator esi = elf_secs.begin ();
1007               esi != elf_secs.end ();
1008               ++esi)
1009          {
1010            secs.push_back (section (*(*esi)));
1011          }
1012        }
1013      }
1014
1015      /*
1016       * This is a valid object file. The file format checks out.
1017       */
1018      valid_ = true;
1019    }
1020
1021    void
1022    object::end ()
1023    {
1024      if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
1025        std::cout << "object:end: " << name ().full () << std::endl;
1026
1027      elf ().end ();
1028    }
1029
1030    bool
1031    object::valid () const
1032    {
1033      return valid_;
1034    }
1035
1036    void
1037    object::load_symbols (rld::symbols::table& symbols, bool local)
1038    {
1039      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1040        std::cout << "object:load-sym: " << name ().full () << std::endl;
1041
1042      rld::symbols::pointers syms;
1043
1044      if (local)
1045      {
1046        elf ().get_symbols (syms, false, true, false, false);
1047
1048        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1049          std::cout << "object:load-sym: local: total "
1050                    << syms.size () << std::endl;
1051
1052        for (symbols::pointers::iterator si = syms.begin ();
1053             si != syms.end ();
1054             ++si)
1055        {
1056          symbols::symbol& sym = *(*si);
1057
1058          if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1059            std::cout << "object:load-sym: local: " << sym << std::endl;
1060
1061          sym.set_object (*this);
1062          symbols.add_local (sym);
1063        }
1064      }
1065
1066      elf ().get_symbols (syms, false, false, true, false);
1067
1068      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1069        std::cout << "object:load-sym: weak: total "
1070                  << syms.size () << std::endl;
1071
1072      for (symbols::pointers::iterator si = syms.begin ();
1073           si != syms.end ();
1074           ++si)
1075      {
1076        symbols::symbol& sym = *(*si);
1077
1078        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1079          std::cout << "object:load-sym: weak: " << sym << std::endl;
1080
1081        sym.set_object (*this);
1082        symbols.add_weak (sym);
1083        externals.push_back (&sym);
1084      }
1085
1086      elf ().get_symbols (syms, false, false, false, true);
1087
1088      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1089        std::cout << "object:load-sym: global: total "
1090                  << syms.size () << std::endl;
1091
1092      for (symbols::pointers::iterator si = syms.begin ();
1093           si != syms.end ();
1094           ++si)
1095      {
1096        symbols::symbol& sym = *(*si);
1097
1098        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1099          std::cout << "object:load-sym: global: " << sym << std::endl;
1100
1101        sym.set_object (*this);
1102        symbols.add_global (sym);
1103        externals.push_back (&sym);
1104      }
1105
1106      elf ().get_symbols (syms, true, false, true, true);
1107
1108      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1109        std::cout << "object:load-sym: unresolved: total "
1110                  << syms.size () << std::endl;
1111
1112      for (symbols::pointers::iterator si = syms.begin ();
1113           si != syms.end ();
1114           ++si)
1115      {
1116        symbols::symbol& sym = *(*si);
1117
1118        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1119        {
1120          std::cout << "object:load-sym: unresolved: ";
1121          sym.output (std::cout);
1122          std::cout << std::endl;
1123        }
1124
1125        unresolved[sym.name ()] = &sym;
1126      }
1127    }
1128
1129    void
1130    object::load_relocations ()
1131    {
1132      if (rld::verbose () >= RLD_VERBOSE_TRACE)
1133        std::cout << "object:load-relocs: " << name ().full () << std::endl;
1134
1135      elf ().load_relocations ();
1136
1137      for (sections::iterator si = secs.begin ();
1138           si != secs.end ();
1139           ++si)
1140      {
1141        section&            sec = *si;
1142        const elf::section& elf_sec = elf ().get_section (sec.index);
1143        sec.load_relocations (elf_sec);
1144      }
1145    }
1146
1147    int
1148    object::references () const
1149    {
1150      if (archive_)
1151        return archive_->references ();
1152      return image::references ();
1153    }
1154
1155    size_t
1156    object::size () const
1157    {
1158      if (archive_)
1159        return archive_->size ();
1160      return image::size ();
1161    }
1162
1163    int
1164    object::fd () const
1165    {
1166      if (archive_)
1167        return archive_->fd ();
1168      return image::fd ();
1169    }
1170
1171    void
1172    object::symbol_referenced ()
1173    {
1174      image::symbol_referenced ();
1175      if (archive_)
1176        archive_->symbol_referenced ();
1177    }
1178
1179    archive*
1180    object::get_archive ()
1181    {
1182      return archive_;
1183    }
1184
1185    rld::symbols::symtab&
1186    object::unresolved_symbols ()
1187    {
1188      return unresolved;
1189    }
1190
1191    rld::symbols::pointers&
1192    object::external_symbols ()
1193    {
1194      return externals;
1195    }
1196
1197    void
1198    object::get_sections (sections& filtered_secs,
1199                          uint32_t  type,
1200                          uint64_t  flags_in,
1201                          uint64_t  flags_out)
1202    {
1203      for (sections::const_iterator si = secs.begin ();
1204           si != secs.end ();
1205           ++si)
1206      {
1207        const section& sec = *si;
1208        if ((type == 0) || (type == sec.type))
1209        {
1210          if ((flags_in == 0) ||
1211              (((sec.flags & flags_in) == flags_in) &&
1212               ((sec.flags & flags_out) == 0)))
1213          {
1214            filtered_secs.push_back (sec);
1215          }
1216        }
1217      }
1218    }
1219
1220    void
1221    object::get_sections (sections& filtered_secs, const std::string& matching_name)
1222    {
1223      for (sections::const_iterator si = secs.begin ();
1224           si != secs.end ();
1225           ++si)
1226      {
1227        const section& sec = *si;
1228        if (sec.name == matching_name)
1229        {
1230          filtered_secs.push_back (sec);
1231        }
1232      }
1233    }
1234
1235    const section&
1236    object::get_section (int index) const
1237    {
1238      for (sections::const_iterator si = secs.begin ();
1239           si != secs.end ();
1240           ++si)
1241      {
1242        const section& sec = *si;
1243        if (sec.index == index)
1244          return sec;
1245      }
1246
1247      throw rld::error ("Section index '" + rld::to_string (index) +
1248                        "' not found: " + name ().full (), "object::get-section");
1249    }
1250
1251    void
1252    object::resolve_set ()
1253    {
1254      resolving_ = true;
1255    }
1256
1257    void
1258    object::resolve_clear ()
1259    {
1260      resolving_ = false;
1261    }
1262
1263    bool
1264    object::resolving () const
1265    {
1266      return resolving_;
1267    }
1268
1269    void
1270    object::resolved_set ()
1271    {
1272      resolved_ = true;
1273    }
1274
1275    bool
1276    object::resolved () const
1277    {
1278      return resolved_;
1279    }
1280
1281    cache::cache ()
1282      : opened (false)
1283    {
1284    }
1285
1286    cache::~cache ()
1287    {
1288      close ();
1289    }
1290
1291    void
1292    cache::open ()
1293    {
1294      if (!opened)
1295      {
1296        collect_object_files ();
1297        archives_begin ();
1298        opened = true;
1299      }
1300    }
1301
1302    void
1303    cache::close ()
1304    {
1305      if (opened)
1306      {
1307        /*
1308         * Must delete the object first as they could depend on archives.
1309         */
1310        for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1311          delete (*oi).second;
1312        for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1313          delete (*ai).second;
1314        opened = false;
1315      }
1316    }
1317
1318    void
1319    cache::add (const std::string& path)
1320    {
1321        paths_.push_back (path);
1322        input (path);
1323    }
1324
1325    void
1326    cache::add (path::paths& paths__)
1327    {
1328      for (path::paths::iterator pi = paths__.begin();
1329           pi != paths__.end();
1330           ++pi)
1331        add (*pi);
1332    }
1333
1334    void
1335    cache::add_libraries (path::paths& paths__)
1336    {
1337      for (path::paths::iterator pi = paths__.begin();
1338           pi != paths__.end();
1339           ++pi)
1340        input (*pi);
1341    }
1342
1343    void
1344    cache::archive_begin (const std::string& path)
1345    {
1346      archives::iterator ai = archives_.find (path);
1347      if (ai != archives_.end ())
1348      {
1349        archive* ar = (*ai).second;
1350        if (!ar->is_open ())
1351        {
1352          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1353            std::cout << "cache:archive-begin: " << path << std::endl;
1354          ar->open ();
1355          ar->begin ();
1356        }
1357      }
1358    }
1359
1360    void
1361    cache::archive_end (const std::string& path)
1362    {
1363      archives::iterator ai = archives_.find (path);
1364      if (ai != archives_.end ())
1365      {
1366        archive* ar = (*ai).second;
1367        if (ar->is_open ())
1368        {
1369          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1370            std::cout << "cache:archive-end: " << path << std::endl;
1371          ar->end ();
1372          ar->close ();
1373        }
1374      }
1375    }
1376
1377    void
1378    cache::archives_begin ()
1379    {
1380      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1381        archive_begin (((*ai).second)->path ());
1382    }
1383
1384    void
1385    cache::archives_end ()
1386    {
1387      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1388        archive_end (((*ai).second)->path ());
1389    }
1390
1391    void
1392    cache::collect_object_files ()
1393    {
1394      for (path::paths::iterator ni = paths_.begin (); ni != paths_.end (); ++ni)
1395        collect_object_files (*ni);
1396    }
1397
1398    void
1399    cache::collect_object_files (const std::string& path)
1400    {
1401      archive* ar = new archive (path);
1402
1403      if (ar->is_valid ())
1404      {
1405        try
1406        {
1407          ar->open ();
1408          ar->load_objects (objects_);
1409          ar->close ();
1410          archives_[path] = ar;
1411        }
1412        catch (...)
1413        {
1414          delete ar;
1415          throw;
1416        }
1417      }
1418      else
1419      {
1420        delete ar;
1421        object* obj = new object (path);
1422        if (!obj->name ().exists ())
1423        {
1424          delete obj;
1425          throw rld::error ("'" + path + "', Not found or a regular file.",
1426                            "file-check");
1427        }
1428        try
1429        {
1430          obj->open ();
1431          obj->begin ();
1432          obj->end ();
1433          obj->close ();
1434          objects_[path] = obj;
1435        }
1436        catch (...)
1437        {
1438          delete obj;
1439          throw;
1440        }
1441      }
1442    }
1443
1444    void
1445    cache::load_symbols (rld::symbols::table& symbols, bool local)
1446    {
1447      if (rld::verbose () >= RLD_VERBOSE_INFO)
1448        std::cout << "cache:load-sym: object files: " << objects_.size ()
1449                  << std::endl;
1450
1451      for (objects::iterator oi = objects_.begin ();
1452           oi != objects_.end ();
1453           ++oi)
1454      {
1455        object* obj = (*oi).second;
1456        obj->open ();
1457        obj->begin ();
1458        obj->load_symbols (symbols, local);
1459        obj->end ();
1460        obj->close ();
1461      }
1462
1463      if (rld::verbose () >= RLD_VERBOSE_INFO)
1464        std::cout << "cache:load-sym: symbols: " << symbols.size ()
1465                  << std::endl;
1466    }
1467
1468    void
1469    cache::output_unresolved_symbols (std::ostream& out)
1470    {
1471      for (objects::iterator oi = objects_.begin ();
1472           oi != objects_.end ();
1473           ++oi)
1474      {
1475        object* obj = (*oi).second;
1476        if (obj)
1477        {
1478          out << obj->name ().full () << ':' << std::endl;
1479          rld::symbols::output (out, obj->unresolved_symbols ());
1480        }
1481      }
1482    }
1483
1484    archives&
1485    cache::get_archives ()
1486    {
1487      return archives_;
1488    }
1489
1490    objects&
1491    cache::get_objects ()
1492    {
1493      return objects_;
1494    }
1495
1496    void
1497    cache::get_objects (object_list& list) const
1498    {
1499      list.clear ();
1500      for (path::paths::const_iterator pi = paths_.begin ();
1501           pi != paths_.end ();
1502           ++pi)
1503      {
1504        objects::const_iterator oi = objects_.find (*pi);
1505        if (oi == objects_.end ())
1506          throw rld::error ("Not located or a valid format", *pi);
1507        list.push_back ((*oi).second);
1508      }
1509    }
1510
1511    const path::paths&
1512    cache::get_paths () const
1513    {
1514      return paths_;
1515    }
1516
1517    int
1518    cache::archive_count () const
1519    {
1520      return archives_.size ();
1521    }
1522
1523    int
1524    cache::object_count () const
1525    {
1526      return objects_.size ();
1527    }
1528
1529    int
1530    cache::path_count () const
1531    {
1532      return paths_.size ();
1533    }
1534
1535    void
1536    cache::get_archive_files (files& afiles)
1537    {
1538      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1539        afiles.push_back ((*ai).second->name ().full ());
1540    }
1541
1542    void
1543    cache::get_object_files (files& ofiles)
1544    {
1545      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1546        ofiles.push_back ((*oi).second->name ());
1547    }
1548
1549    void
1550    cache::output_archive_files (std::ostream& out)
1551    {
1552      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1553        out << ' ' << (*ai).second->name ().full () << std::endl;
1554    }
1555
1556    void
1557    cache::output_object_files (std::ostream& out)
1558    {
1559      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1560        out << ' ' << (*oi).second->name ().full () << std::endl;
1561    }
1562
1563    void
1564    cache::input (const std::string& path)
1565    {
1566      if (opened)
1567      {
1568        collect_object_files (path);
1569        archive_begin (path);
1570      }
1571    }
1572
1573    void
1574    find_libraries (path::paths& libraries,
1575                    path::paths& libpaths,
1576                    path::paths& libs)
1577    {
1578      if (rld::verbose () >= RLD_VERBOSE_INFO)
1579        std::cout << "Finding libraries:" << std::endl;
1580      libraries.clear ();
1581      for (path::paths::size_type l = 0; l < libs.size (); ++l)
1582      {
1583        std::string lib = "lib" + libs[l] + ".a";
1584        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
1585          std::cout << " searching: " << lib << std::endl;
1586        bool found = false;
1587        for (path::paths::size_type p = 0; p < libpaths.size (); ++p)
1588        {
1589          std::string plib;
1590          path::path_join (libpaths[p], lib, plib);
1591          if (rld::verbose () >= RLD_VERBOSE_DETAILS)
1592              std::cout << " checking: " << plib << std::endl;
1593          if (path::check_file (plib))
1594          {
1595            if (rld::verbose () >= RLD_VERBOSE_INFO)
1596              std::cout << " found: " << plib << std::endl;
1597            libraries.push_back (plib);
1598            found = true;
1599            break;
1600          }
1601        }
1602
1603        if (!found)
1604          throw rld::error ("Not found", lib);
1605      }
1606    }
1607
1608  }
1609}
Note: See TracBrowser for help on using the repository browser.