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

5
Last change on this file since 562e98c was b73f905, checked in by Chris Johns <chrisj@…>, on 05/08/18 at 05:09:46

rtemstoolkit/elf,files: Catch exceptions in destructors.

Catch exceptions in destructures and print a message to avoid
an unhandled exception happening in an exception stack unwind.

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