source: rtems-tools/linkers/rld-files.cpp @ 53221a0

4.104.115
Last change on this file since 53221a0 was 53221a0, checked in by Chris Johns <chrisj@…>, on 12/18/12 at 09:52:18

Add object::get_section.

Add a method to return a section given the ELF section index.

Add more trace output for debugging.

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