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

4.104.11
Last change on this file since 87e0e76 was 87e0e76, checked in by Chris Johns <chrisj@…>, on Sep 13, 2014 at 2:09:16 AM

Refactor code into the RTEMS Toolkit.

  • Property mode set to 100644
File size: 37.3 KB
RevLine 
[ec24a37]1/*
[977c3de]2 * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
[ec24a37]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.
[977c3de]7 *
[ec24a37]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
[90d8d43]21#include <algorithm>
22
[ec24a37]23#include <errno.h>
24#include <fcntl.h>
25#include <stdio.h>
26#include <string.h>
27#include <sys/stat.h>
[2ce23a3]28#include <unistd.h>
[ec24a37]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;
[977c3de]51
[ec24a37]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)
[977c3de]80      : aname_ (aname),
[ec24a37]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    {
[40fd7a0]156      return !aname_.empty () || !oname_.empty ();
[ec24a37]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 ())
[40fd7a0]168        result = path::check_file (p);
[ec24a37]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    }
[977c3de]179
180    const std::string
[ec24a37]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    {
[40fd7a0]200      return rld::path::basename (full ());
[ec24a37]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),
[a5fcdd5]230        fd_ (-1),
231        symbol_refs (0),
232        writable (false)
[ec24a37]233    {
234    }
235
236    image::image (const std::string& path, bool is_object)
237      : name_ (path, is_object),
238        references_ (0),
239        fd_ (-1),
[977c3de]240        symbol_refs (0),
[fd8a2c5]241        writable (false)
[ec24a37]242    {
243    }
244
245    image::image ()
246      : references_ (0),
247        fd_ (-1),
[a5fcdd5]248        symbol_refs (0),
249        writable (false)
[ec24a37]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
[fd8a2c5]269    image::open (bool writable_)
[ec24a37]270    {
271      const std::string path = name_.path ();
272
273      if (path.empty ())
[977c3de]274        throw rld::error ("No file name", "open:" + path);
[ec24a37]275
[53221a0]276      if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
[a5fcdd5]277        std::cout << "image::open:  " << name (). full ()
278                  << " refs:" << references_ + 1
[fd8a2c5]279                  << " writable:" << (char*) (writable_ ? "yes" : "no")
[a5fcdd5]280                  << std::endl;
[ec24a37]281
282      if (fd_ < 0)
283      {
[fd8a2c5]284        writable = writable_;
[977c3de]285
[fd8a2c5]286        if (writable)
[ec24a37]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      }
[977c3de]293      else
294      {
[fd8a2c5]295        if (writable_ != writable)
[977c3de]296          throw rld::error ("Cannot change write status", "open:" + path);
297      }
[ec24a37]298
299      ++references_;
300    }
301
302    void
303    image::close ()
304    {
305      if (references_ > 0)
306      {
[53221a0]307        if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
[ec24a37]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
[fe19d06]321    image::read (void* buffer_, size_t size)
[ec24a37]322    {
[fe19d06]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      {
[90d8d43]328        const ssize_t rsize = ::read (fd (), buffer, to_read);
[fe19d06]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;
[ec24a37]338    }
[977c3de]339
[ec24a37]340    ssize_t
[fe19d06]341    image::write (const void* buffer_, size_t size)
[ec24a37]342    {
[90d8d43]343      const uint8_t* buffer = static_cast <const uint8_t*> (buffer_);
[fe19d06]344      size_t         have_written = 0;
345      size_t         to_write = size;
346      while (have_written < size)
347      {
[90d8d43]348        const ssize_t wsize = ::write (fd (), buffer, to_write);
[fe19d06]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;
[ec24a37]356    }
[977c3de]357
[ec24a37]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    }
[977c3de]364
[ec24a37]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    }
[977c3de]371
[ec24a37]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    }
[977c3de]378
[ec24a37]379    const file&
380    image::name () const
381    {
382      return name_;
383    }
384
385    int
[977c3de]386    image::references () const
[ec24a37]387    {
388      return references_;
389    }
390
391    size_t
[977c3de]392    image::size () const
[ec24a37]393    {
394      return name ().size ();
395    }
396
397    int
[977c3de]398    image::fd () const
[ec24a37]399    {
400      return fd_;
401    }
402
[977c3de]403    rld::elf::file&
404    image::elf ()
[ec24a37]405    {
406      return elf_;
407    }
408
409    void
410    image::symbol_referenced ()
411    {
412      ++symbol_refs;
413    }
[977c3de]414
[ec24a37]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;
[fe19d06]426
427      if (size == 0)
428        size = in.name ().size ();
429
[ec24a37]430      try
431      {
432        buffer = new uint8_t[COPY_FILE_BUFFER_SIZE];
433        while (size)
434        {
[977c3de]435          /*
436           * @fixme the reading and writing are not POSIX; sigints could split them.
437           */
438
[ec24a37]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    {
[f1cf3a9]507      end ();
[ec24a37]508      close ();
509    }
510
[977c3de]511    void
512    archive::begin ()
513    {
[f1cf3a9]514      if (references () == 1)
515      {
516        elf ().begin (name ().full (), fd ());
[977c3de]517
[f1cf3a9]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      }
[977c3de]525    }
526
527    void
528    archive::end ()
529    {
[f1cf3a9]530      if (references () == 1)
531        elf ().end ();
[977c3de]532    }
533
[ec24a37]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         */
[977c3de]569        size =
570          (scan_decimal (&header[rld_archive_size],
[ec24a37]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                {
[977c3de]614                  size_t esize =
[ec24a37]615                    (scan_decimal (&header[rld_archive_size],
616                                   rld_archive_size_size) + 1) & ~1;
617                  off += esize + rld_archive_fhdr_size;
[977c3de]618
[ec24a37]619                  if (!read_header (off, &header[0]))
620                    throw rld::error ("No GNU extended file name section found",
621                                      "get-names:" + name ().path ());
[977c3de]622
[ec24a37]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 ());
[977c3de]682
[ec24a37]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;
[5eb6604]690      while ((*end != '\0') && (*end != '/') && (*end != '\n'))
[ec24a37]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));
[977c3de]714
[ec24a37]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    {
[53221a0]735      if (rld::verbose () >= RLD_VERBOSE_DETAILS)
[fe19d06]736        std::cout << "archive::create: " << name ().full ()
737                  << ", objects: " << objects.size () << std::endl;
738
[ec24a37]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;
[977c3de]749
[ec24a37]750        for (object_list::iterator oi = objects.begin ();
751             oi != objects.end ();
752             ++oi)
753        {
754          object& obj = *(*oi);
[40fd7a0]755          const std::string&  oname = path::basename (obj.name ().oname ());
[5eb6604]756          if (oname.length () >= rld_archive_fname_size)
[ec24a37]757            extended_file_names += oname + '\n';
758        }
759
760        if (!extended_file_names.empty ())
761        {
[5eb6604]762          if (extended_file_names.length () & 1)
763          {
764            extended_file_names += ' ';
765          }
[ec24a37]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          {
[40fd7a0]780            std::string oname = path::basename (obj.name ().oname ());
[ec24a37]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
[5eb6604]787            if (oname.length () >= rld_archive_fname_size)
[ec24a37]788            {
[fe19d06]789              size_t pos = extended_file_names.find (oname + '\n');
[ec24a37]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            }
[5eb6604]796            else oname += '/';
[ec24a37]797
[5eb6604]798            write_header (oname, 0, 0, 0, 0666, (obj.name ().size () + 1) & ~1);
[ec24a37]799            obj.seek (0);
[fe19d06]800            copy_file (obj, *this);
[5eb6604]801            if (obj.name ().size () & 1)
802              write ("\n", 1);
[ec24a37]803          }
804          catch (...)
805          {
806            obj.close ();
807            throw;
808          }
809
810          obj.close ();
811        }
812      }
813      catch (...)
814      {
815        close ();
816        throw;
817      }
[977c3de]818
[ec24a37]819      close ();
820    }
821
[90d8d43]822    relocation::relocation (const elf::relocation& er)
[42f766f]823      : offset (er.offset ()),
[90d8d43]824        type (er.type ()),
825        info (er.info ()),
[42f766f]826        addend (er.addend ()),
827        symname (er.symbol ().name ()),
828        symtype (er.symbol ().type ()),
829        symsect (er.symbol ().section_index ()),
[c14133e]830        symvalue (er.symbol ().value ()),
831        symbinding (er.symbol ().binding ())
[90d8d43]832    {
833    }
834
[a5fcdd5]835    section::section (const elf::section& es)
836      : name (es.name ()),
[662c504]837        index (es.index ()),
[a5fcdd5]838        type (es.type ()),
839        size (es.size ()),
840        alignment (es.alignment ()),
841        link (es.link ()),
842        info (es.info ()),
843        flags (es.flags ()),
[90d8d43]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      }
[42f766f]859      rela = es.get_reloc_type ();
[a5fcdd5]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
[662c504]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
[ec24a37]897    object::object (archive& archive_, file& name_)
898      : image (name_),
[a5fcdd5]899        archive_ (&archive_),
[544de91]900        valid_ (false),
901        resolving_ (false),
902        resolved_ (false)
[ec24a37]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),
[a5fcdd5]910        archive_ (0),
[544de91]911        valid_ (false),
912        resolving_ (false),
913        resolved_ (false)
[ec24a37]914    {
915      if (!name ().is_valid ())
916        throw rld_error_at ("name is empty");
917    }
918
919    object::object ()
[a5fcdd5]920      : archive_ (0),
[544de91]921        valid_ (false),
922        resolving_ (false),
923        resolved_ (false)
[ec24a37]924    {
925    }
926
927    object::~object ()
928    {
929      end ();
930      close ();
931    }
932
933    void
[596e5fa]934    object::open (bool writable)
[ec24a37]935    {
936      if (archive_)
[596e5fa]937      {
938        if (writable)
939          throw rld_error_at ("object files in archives are not writable");
[ec24a37]940        archive_->open ();
[596e5fa]941      }
[ec24a37]942      else
[596e5fa]943        image::open (writable);
[ec24a37]944    }
945
946    void
947    object::close ()
948    {
949      if (archive_)
[f1cf3a9]950      {
951        archive_->end ();
[ec24a37]952        archive_->close ();
[f1cf3a9]953      }
[ec24a37]954      else
[f1cf3a9]955      {
956        end ();
[ec24a37]957        image::close ();
[f1cf3a9]958      }
[ec24a37]959    }
960
961    void
962    object::begin ()
963    {
964      /*
[977c3de]965       * Begin a session.
966       */
[a5fcdd5]967
[53221a0]968      if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
[a5fcdd5]969        std::cout << "object:begin: " << name ().full () << " in-archive:"
970                  << ((char*) (archive_ ? "yes" : "no")) << std::endl;
971
[977c3de]972      if (archive_)
973        elf ().begin (name ().full (), archive_->elf(), name ().offset ());
974      else
[fd8a2c5]975        elf ().begin (name ().full (), fd (), is_writable ());
[977c3de]976
977      /*
978       * Cannot be an archive.
[ec24a37]979       */
[977c3de]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       */
[fd8a2c5]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 ());
[a5fcdd5]992
[fd8a2c5]993        elf::check_file (elf ());
[a5fcdd5]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        }
[fd8a2c5]1012      }
[a5fcdd5]1013
1014      /*
1015       * This is a valid object file. The file format checks out.
1016       */
1017      valid_ = true;
[ec24a37]1018    }
1019
1020    void
1021    object::end ()
1022    {
[53221a0]1023      if (rld::verbose () >= RLD_VERBOSE_TRACE_FILE)
[a5fcdd5]1024        std::cout << "object:end: " << name ().full () << std::endl;
1025
[977c3de]1026      elf ().end ();
[ec24a37]1027    }
1028
[a5fcdd5]1029    bool
1030    object::valid () const
1031    {
1032      return valid_;
1033    }
1034
[ec24a37]1035    void
1036    object::load_symbols (rld::symbols::table& symbols, bool local)
1037    {
[53221a0]1038      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
[ec24a37]1039        std::cout << "object:load-sym: " << name ().full () << std::endl;
1040
[977c3de]1041      rld::symbols::pointers syms;
1042
[544de91]1043      elf ().get_symbols (syms, false, local, false, true);
[977c3de]1044
[53221a0]1045      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
[977c3de]1046        std::cout << "object:load-sym: exported: total "
1047                  << syms.size () << std::endl;
1048
1049      for (symbols::pointers::iterator si = syms.begin ();
1050           si != syms.end ();
1051           ++si)
1052      {
1053        symbols::symbol& sym = *(*si);
1054
[a5fcdd5]1055        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
[53221a0]1056          std::cout << "object:load-sym: exported: " << sym << std::endl;
[977c3de]1057
1058        sym.set_object (*this);
[544de91]1059        symbols.add_external (sym);
[977c3de]1060        externals.push_back (&sym);
1061      }
1062
[544de91]1063      elf ().get_symbols (syms, false, false, true, false);
1064
1065      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1066        std::cout << "object:load-sym: weak: total "
1067                  << syms.size () << std::endl;
1068
1069      for (symbols::pointers::iterator si = syms.begin ();
1070           si != syms.end ();
1071           ++si)
1072      {
1073        symbols::symbol& sym = *(*si);
1074
1075        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
1076          std::cout << "object:load-sym: weak: " << sym << std::endl;
1077
1078        sym.set_object (*this);
1079        symbols.add_weak (sym);
1080        externals.push_back (&sym);
1081      }
1082
1083      elf ().get_symbols (syms, true, false, true, true);
[977c3de]1084
[53221a0]1085      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
[977c3de]1086        std::cout << "object:load-sym: unresolved: total "
1087                  << syms.size () << std::endl;
1088
1089      for (symbols::pointers::iterator si = syms.begin ();
1090           si != syms.end ();
1091           ++si)
1092      {
1093        symbols::symbol& sym = *(*si);
1094
[a5fcdd5]1095        if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
[977c3de]1096        {
1097          std::cout << "object:load-sym: unresolved: ";
1098          sym.output (std::cout);
1099          std::cout << std::endl;
1100        }
1101
1102        unresolved[sym.name ()] = &sym;
1103      }
[ec24a37]1104    }
[977c3de]1105
[90d8d43]1106    void
1107    object::load_relocations ()
1108    {
[d54e81c]1109      if (rld::verbose () >= RLD_VERBOSE_TRACE)
[90d8d43]1110        std::cout << "object:load-relocs: " << name ().full () << std::endl;
1111
1112      elf ().load_relocations ();
1113
1114      for (sections::iterator si = secs.begin ();
1115           si != secs.end ();
1116           ++si)
1117      {
1118        section&            sec = *si;
1119        const elf::section& elf_sec = elf ().get_section (sec.index);
1120        sec.load_relocations (elf_sec);
1121      }
1122    }
1123
[ec24a37]1124    int
[977c3de]1125    object::references () const
[ec24a37]1126    {
1127      if (archive_)
1128        return archive_->references ();
1129      return image::references ();
1130    }
1131
1132    size_t
[977c3de]1133    object::size () const
[ec24a37]1134    {
1135      if (archive_)
1136        return archive_->size ();
1137      return image::size ();
1138    }
1139
1140    int
[977c3de]1141    object::fd () const
[ec24a37]1142    {
1143      if (archive_)
1144        return archive_->fd ();
1145      return image::fd ();
1146    }
1147
1148    void
1149    object::symbol_referenced ()
1150    {
1151      image::symbol_referenced ();
1152      if (archive_)
1153        archive_->symbol_referenced ();
1154    }
[977c3de]1155
[ec24a37]1156    archive*
1157    object::get_archive ()
1158    {
1159      return archive_;
1160    }
1161
[544de91]1162    rld::symbols::symtab&
[ec24a37]1163    object::unresolved_symbols ()
1164    {
1165      return unresolved;
1166    }
1167
[977c3de]1168    rld::symbols::pointers&
[ec24a37]1169    object::external_symbols ()
1170    {
1171      return externals;
1172    }
1173
[a5fcdd5]1174    void
1175    object::get_sections (sections& filtered_secs,
1176                          uint32_t  type,
1177                          uint64_t  flags_in,
1178                          uint64_t  flags_out)
1179    {
1180      for (sections::const_iterator si = secs.begin ();
1181           si != secs.end ();
1182           ++si)
1183      {
1184        const section& sec = *si;
1185        if ((type == 0) || (type == sec.type))
1186        {
1187          if ((flags_in == 0) ||
1188              (((sec.flags & flags_in) == flags_in) &&
1189               ((sec.flags & flags_out) == 0)))
1190          {
1191            filtered_secs.push_back (sec);
1192          }
1193        }
1194      }
1195    }
1196
1197    void
1198    object::get_sections (sections& filtered_secs, const std::string& matching_name)
1199    {
1200      for (sections::const_iterator si = secs.begin ();
1201           si != secs.end ();
1202           ++si)
1203      {
1204        const section& sec = *si;
1205        if (sec.name == matching_name)
1206        {
1207          filtered_secs.push_back (sec);
1208        }
1209      }
1210    }
1211
[53221a0]1212    const section&
1213    object::get_section (int index) const
1214    {
1215      for (sections::const_iterator si = secs.begin ();
1216           si != secs.end ();
1217           ++si)
1218      {
1219        const section& sec = *si;
1220        if (sec.index == index)
1221          return sec;
1222      }
1223
1224      throw rld::error ("Section index '" + rld::to_string (index) +
1225                        "' not found: " + name ().full (), "object::get-section");
1226    }
1227
[544de91]1228    void
1229    object::resolve_set ()
1230    {
1231      resolving_ = true;
1232    }
1233
1234    void
1235    object::resolve_clear ()
1236    {
1237      resolving_ = false;
1238    }
1239
1240    bool
1241    object::resolving () const
1242    {
1243      return resolving_;
1244    }
1245
1246    void
1247    object::resolved_set ()
1248    {
1249      resolved_ = true;
1250    }
1251
1252    bool
1253    object::resolved () const
1254    {
1255      return resolved_;
1256    }
1257
[ec24a37]1258    cache::cache ()
1259      : opened (false)
1260    {
1261    }
1262
1263    cache::~cache ()
1264    {
1265      close ();
1266    }
1267
1268    void
1269    cache::open ()
1270    {
1271      if (!opened)
1272      {
1273        collect_object_files ();
1274        archives_begin ();
1275        opened = true;
1276      }
1277    }
1278
1279    void
1280    cache::close ()
1281    {
1282      if (opened)
1283      {
1284        /*
1285         * Must delete the object first as they could depend on archives.
1286         */
1287        for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1288          delete (*oi).second;
1289        for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1290          delete (*ai).second;
1291        opened = false;
1292      }
1293    }
1294
1295    void
1296    cache::add (const std::string& path)
1297    {
1298        paths_.push_back (path);
1299        input (path);
1300    }
1301
1302    void
[40fd7a0]1303    cache::add (path::paths& paths__)
[ec24a37]1304    {
[40fd7a0]1305      for (path::paths::iterator pi = paths__.begin();
[ec24a37]1306           pi != paths__.end();
1307           ++pi)
1308        add (*pi);
1309    }
1310
1311    void
[40fd7a0]1312    cache::add_libraries (path::paths& paths__)
[ec24a37]1313    {
[40fd7a0]1314      for (path::paths::iterator pi = paths__.begin();
[ec24a37]1315           pi != paths__.end();
1316           ++pi)
1317        input (*pi);
1318    }
1319
1320    void
1321    cache::archive_begin (const std::string& path)
1322    {
1323      archives::iterator ai = archives_.find (path);
1324      if (ai != archives_.end ())
1325      {
1326        archive* ar = (*ai).second;
1327        if (!ar->is_open ())
1328        {
1329          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1330            std::cout << "cache:archive-begin: " << path << std::endl;
1331          ar->open ();
[977c3de]1332          ar->begin ();
[ec24a37]1333        }
1334      }
1335    }
1336
1337    void
1338    cache::archive_end (const std::string& path)
1339    {
1340      archives::iterator ai = archives_.find (path);
1341      if (ai != archives_.end ())
1342      {
1343        archive* ar = (*ai).second;
1344        if (ar->is_open ())
1345        {
1346          if (rld::verbose () >= RLD_VERBOSE_TRACE)
1347            std::cout << "cache:archive-end: " << path << std::endl;
[977c3de]1348          ar->end ();
[ec24a37]1349          ar->close ();
1350        }
1351      }
1352    }
1353
1354    void
1355    cache::archives_begin ()
1356    {
1357      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1358        archive_begin (((*ai).second)->path ());
1359    }
1360
1361    void
1362    cache::archives_end ()
1363    {
1364      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1365        archive_end (((*ai).second)->path ());
1366    }
[977c3de]1367
[ec24a37]1368    void
1369    cache::collect_object_files ()
1370    {
[40fd7a0]1371      for (path::paths::iterator ni = paths_.begin (); ni != paths_.end (); ++ni)
[ec24a37]1372        collect_object_files (*ni);
1373    }
1374
1375    void
1376    cache::collect_object_files (const std::string& path)
1377    {
1378      archive* ar = new archive (path);
1379
1380      if (ar->is_valid ())
1381      {
1382        try
1383        {
1384          ar->open ();
1385          ar->load_objects (objects_);
1386          ar->close ();
[a5fcdd5]1387          archives_[path] = ar;
[ec24a37]1388        }
1389        catch (...)
1390        {
1391          delete ar;
1392          throw;
1393        }
1394      }
1395      else
1396      {
1397        delete ar;
1398        object* obj = new object (path);
1399        if (!obj->name ().exists ())
1400        {
1401          delete obj;
1402          throw rld::error ("'" + path + "', Not found or a regular file.",
1403                            "file-check");
1404        }
1405        try
1406        {
1407          obj->open ();
1408          obj->begin ();
1409          obj->end ();
1410          obj->close ();
1411          objects_[path] = obj;
1412        }
1413        catch (...)
1414        {
1415          delete obj;
1416          throw;
1417        }
1418      }
1419    }
1420
1421    void
1422    cache::load_symbols (rld::symbols::table& symbols, bool local)
1423    {
[f1cf3a9]1424      if (rld::verbose () >= RLD_VERBOSE_INFO)
1425        std::cout << "cache:load-sym: object files: " << objects_.size ()
1426                  << std::endl;
1427
[a5fcdd5]1428      for (objects::iterator oi = objects_.begin ();
1429           oi != objects_.end ();
1430           ++oi)
[f1cf3a9]1431      {
[a5fcdd5]1432        object* obj = (*oi).second;
1433        obj->open ();
1434        obj->begin ();
1435        obj->load_symbols (symbols, local);
1436        obj->end ();
1437        obj->close ();
[ec24a37]1438      }
[f1cf3a9]1439
1440      if (rld::verbose () >= RLD_VERBOSE_INFO)
1441        std::cout << "cache:load-sym: symbols: " << symbols.size ()
1442                  << std::endl;
[ec24a37]1443    }
1444
1445    void
1446    cache::output_unresolved_symbols (std::ostream& out)
1447    {
1448      for (objects::iterator oi = objects_.begin ();
1449           oi != objects_.end ();
1450           ++oi)
1451      {
1452        object* obj = (*oi).second;
1453        if (obj)
1454        {
1455          out << obj->name ().full () << ':' << std::endl;
1456          rld::symbols::output (out, obj->unresolved_symbols ());
1457        }
1458      }
1459    }
1460
1461    archives&
1462    cache::get_archives ()
1463    {
1464      return archives_;
1465    }
[977c3de]1466
[ec24a37]1467    objects&
1468    cache::get_objects ()
1469    {
1470      return objects_;
1471    }
1472
1473    void
[b770b0c]1474    cache::get_objects (object_list& list) const
[ec24a37]1475    {
1476      list.clear ();
[40fd7a0]1477      for (path::paths::const_iterator pi = paths_.begin ();
[ec24a37]1478           pi != paths_.end ();
1479           ++pi)
1480      {
[b770b0c]1481        objects::const_iterator oi = objects_.find (*pi);
[ec24a37]1482        if (oi == objects_.end ())
1483          throw rld_error_at ("path not found in objects");
1484        list.push_back ((*oi).second);
1485      }
1486    }
1487
[40fd7a0]1488    const path::paths&
[ec24a37]1489    cache::get_paths () const
1490    {
1491      return paths_;
1492    }
1493
1494    int
1495    cache::archive_count () const
1496    {
1497      return archives_.size ();
1498    }
1499
1500    int
1501    cache::object_count () const
1502    {
1503      return objects_.size ();
1504    }
1505
1506    int
1507    cache::path_count () const
1508    {
1509      return paths_.size ();
1510    }
1511
1512    void
1513    cache::get_archive_files (files& afiles)
1514    {
1515      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1516        afiles.push_back ((*ai).second->name ().full ());
1517    }
1518
1519    void
1520    cache::get_object_files (files& ofiles)
1521    {
1522      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1523        ofiles.push_back ((*oi).second->name ());
1524    }
1525
1526    void
1527    cache::output_archive_files (std::ostream& out)
1528    {
1529      for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai)
1530        out << ' ' << (*ai).second->name ().full () << std::endl;
1531    }
1532
1533    void
1534    cache::output_object_files (std::ostream& out)
1535    {
1536      for (objects::iterator oi = objects_.begin (); oi != objects_.end (); ++oi)
1537        out << ' ' << (*oi).second->name ().full () << std::endl;
1538    }
1539
1540    void
1541    cache::input (const std::string& path)
1542    {
1543      if (opened)
1544      {
1545        collect_object_files (path);
1546        archive_begin (path);
1547      }
1548    }
1549
1550    void
[40fd7a0]1551    find_libraries (path::paths& libraries,
1552                    path::paths& libpaths,
1553                    path::paths& libs)
[ec24a37]1554    {
1555      if (rld::verbose () >= RLD_VERBOSE_INFO)
[fd8a2c5]1556        std::cout << "Finding libraries:." << std::endl;
[ec24a37]1557      libraries.clear ();
[40fd7a0]1558      for (path::paths::size_type l = 0; l < libs.size (); ++l)
[ec24a37]1559      {
1560        std::string lib = "lib" + libs[l] + ".a";
1561        if (rld::verbose () >= RLD_VERBOSE_DETAILS)
[fd8a2c5]1562          std::cout << " searching: " << lib << std::endl;
[ec24a37]1563        bool found = false;
[40fd7a0]1564        for (path::paths::size_type p = 0; p < libpaths.size (); ++p)
[ec24a37]1565        {
1566          std::string plib;
[40fd7a0]1567          path::path_join (libpaths[p], lib, plib);
[ec24a37]1568          if (rld::verbose () >= RLD_VERBOSE_DETAILS)
[fd8a2c5]1569              std::cout << " checking: " << plib << std::endl;
[40fd7a0]1570          if (path::check_file (plib))
[ec24a37]1571          {
1572            if (rld::verbose () >= RLD_VERBOSE_INFO)
[fd8a2c5]1573              std::cout << " found: " << plib << std::endl;
[ec24a37]1574            libraries.push_back (plib);
1575            found = true;
1576            break;
1577          }
1578        }
1579
1580        if (!found)
1581          throw rld::error ("Not found", lib);
1582      }
1583    }
1584
1585  }
1586}
Note: See TracBrowser for help on using the repository browser.