source: rtems-tools/rtemstoolkit/rld-elf.cpp @ 156b227

5
Last change on this file since 156b227 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: 30.2 KB
Line 
1/*
2 * Copyright (c) 2011-2012, 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 * @file
18 *
19 * @ingroup rtems-ld
20 *
21 * @brief RTEMS Linker ELF module manages the ELF format images.
22 *
23 */
24
25#include <string.h>
26
27#include <rld.h>
28
29namespace rld
30{
31  namespace elf
32  {
33    /**
34     * Throw an ELF error.
35     *
36     * @param where Where the error is raised.
37     */
38    void libelf_error (const std::string& where)
39    {
40      throw rld::error (::elf_errmsg (-1), "libelf:" + where);
41    }
42
43    /**
44     * We record the first class, machine and .. type of object file we get the
45     * header of and all header must match. We cannot mix object module types.
46     */
47    static unsigned int elf_object_class = ELFCLASSNONE;
48    static unsigned int elf_object_machinetype = EM_NONE;
49    static unsigned int elf_object_datatype = ELFDATANONE;
50
51    /**
52     * A single place to initialise the libelf library. This must be called
53     * before any libelf API calls are made.
54     */
55    static void
56    libelf_initialise ()
57    {
58      static bool libelf_initialised = false;
59      if (!libelf_initialised)
60      {
61        if (::elf_version (EV_CURRENT) == EV_NONE)
62          libelf_error ("initialisation");
63        libelf_initialised = true;
64      }
65    }
66
67    relocation::relocation (const symbols::symbol& sym,
68                            elf_addr               offset,
69                            elf_xword              info,
70                            elf_sxword             addend)
71      : sym (&sym),
72        offset_ (offset),
73        info_ (info),
74        addend_ (addend)
75    {
76    }
77
78    relocation::relocation ()
79      : sym (0),
80        offset_ (0),
81        info_ (0),
82        addend_ (0)
83    {
84    }
85
86    elf_addr
87    relocation::offset () const
88    {
89      return offset_;
90    }
91
92    uint32_t
93    relocation::type () const
94    {
95      return GELF_R_TYPE (info_);
96    }
97
98    elf_xword
99    relocation::info () const
100    {
101      return info_;
102    }
103
104    elf_sxword
105    relocation::addend () const
106    {
107      return addend_;
108    }
109
110    const symbols::symbol&
111    relocation::symbol () const
112    {
113      if (sym)
114        return *sym;
115      throw rld::error ("no symbol", "elf:relocation");
116    }
117
118    section::section (file&              file_,
119                      int                index_,
120                      const std::string& name_,
121                      elf_word           type,
122                      elf_xword          alignment,
123                      elf_xword          flags,
124                      elf_addr           addr,
125                      elf_off            offset,
126                      elf_xword          size,
127                      elf_word           link,
128                      elf_word           info,
129                      elf_xword          entry_size)
130      : file_ (&file_),
131        index_ (index_),
132        name_ (name_),
133        scn (0),
134        data_ (0),
135        rela (false)
136    {
137      if (!file_.is_writable ())
138        throw rld::error ("not writable",
139                          "elf:section" + file_.name () + " (" + name_ + ')');
140
141      scn = ::elf_newscn (file_.get_elf ());
142      if (!scn)
143        libelf_error ("elf_newscn: " + name_ + " (" + file_.name () + ')');
144
145      if (::gelf_getshdr(scn, &shdr) == 0)
146        libelf_error ("gelf_getshdr: " + name_ + " (" + file_.name () + ')');
147
148      shdr.sh_name = 0;
149      shdr.sh_type = type;
150      shdr.sh_flags = flags;
151      shdr.sh_addr = addr;
152      shdr.sh_offset = offset;
153      shdr.sh_size = size;
154      shdr.sh_link = link;
155      shdr.sh_info = info;
156      shdr.sh_addralign = alignment;
157      shdr.sh_entsize = entry_size;
158
159      if (type == SHT_NOBITS)
160        add_data (ELF_T_BYTE, alignment, size);
161
162      if (!gelf_update_shdr (scn, &shdr))
163        libelf_error ("gelf_update_shdr: " + name_ + " (" + file_.name () + ')');
164    }
165
166    section::section (file& file_, int index_)
167      : file_ (&file_),
168        index_ (index_),
169        scn (0),
170        data_ (0),
171        rela (false)
172    {
173      memset (&shdr, 0, sizeof (shdr));
174
175      scn = ::elf_getscn (file_.get_elf (), index_);
176      if (!scn)
177        libelf_error ("elf_getscn: " + file_.name ());
178
179      if (!::gelf_getshdr (scn, &shdr))
180        libelf_error ("gelf_getshdr: " + file_.name ());
181
182      if (shdr.sh_type != SHT_NULL)
183      {
184        name_ = file_.get_string (shdr.sh_name);
185        data_ = ::elf_getdata (scn, 0);
186        if (!data_)
187        {
188          data_ = ::elf_rawdata (scn, 0);
189          if (!data_)
190            libelf_error ("elf_getdata: " + name_ + '(' + file_.name () + ')');
191        }
192      }
193
194      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
195        std::cout << "elf::section: index=" << index ()
196                  << " name='" << name () << "'"
197                  << " size=" << size ()
198                  << " align=" << alignment ()
199                  << " flags=0x" << std::hex << flags () << std::dec
200                  << std::endl;
201    }
202
203    section::section (const section& orig)
204      : file_ (orig.file_),
205        index_ (orig.index_),
206        name_ (orig.name_),
207        scn (orig.scn),
208        shdr (orig.shdr),
209        data_ (orig.data_),
210        rela (orig.rela),
211        relocs (orig.relocs)
212    {
213    }
214
215    section::section ()
216      : file_ (0),
217        index_ (-1),
218        scn (0),
219        data_ (0),
220        rela (false)
221    {
222      memset (&shdr, 0, sizeof (shdr));
223    }
224
225    void
226    section::add_data (elf_type  type,
227                       elf_xword alignment,
228                       elf_xword size,
229                       void*     buffer,
230                       elf_off   offset)
231    {
232      check_writable ("add_data");
233
234      data_ = ::elf_newdata(scn);
235      if (!data_)
236        libelf_error ("elf_newdata: " + name_ + " (" + file_->name () + ')');
237
238      data_->d_type = type;
239      data_->d_off = offset;
240      data_->d_size = size;
241      data_->d_align = alignment;
242      data_->d_version = EV_CURRENT;
243      data_->d_buf = buffer;
244
245      if (!gelf_update_shdr (scn, &shdr))
246        libelf_error ("gelf_update_shdr: " + name_ + " (" + file_->name () + ')');
247    }
248
249    int
250    section::index () const
251    {
252      check ("index");
253      return index_;
254    }
255
256    const std::string&
257    section::name () const
258    {
259      check ("name");
260      return name_;
261    }
262
263    elf_data*
264    section::data ()
265    {
266      check ("data");
267      return data_;
268    }
269
270    elf_word
271    section::type () const
272    {
273      check ("type");
274      return shdr.sh_type;
275    }
276
277    elf_xword
278    section::flags () const
279    {
280      check ("flags");
281      return shdr.sh_flags;
282    }
283
284    elf_addr
285    section::address () const
286    {
287      check ("address");
288      return shdr.sh_addr;
289    }
290
291    elf_xword
292    section::alignment () const
293    {
294      check ("alignment");
295      return shdr.sh_addralign;
296    }
297
298    elf_off
299    section::offset () const
300    {
301      check ("offset");
302      return shdr.sh_offset;
303    }
304
305    elf_word
306    section::link () const
307    {
308      check ("link");
309      return shdr.sh_link;
310    }
311
312    elf_word
313    section::info () const
314    {
315      check ("info");
316      return shdr.sh_info;
317    }
318
319    elf_xword
320    section::size () const
321    {
322      check ("size");
323      return shdr.sh_size;
324    }
325
326    elf_xword
327    section::entry_size () const
328    {
329      check ("entry_size");
330      return shdr.sh_entsize;
331    }
332
333    int
334    section::entries () const
335    {
336      return size () / entry_size ();
337    }
338
339    bool
340    section::get_reloc_type () const
341    {
342      return rela;
343    }
344
345    void
346    section::set_name (unsigned int index)
347    {
348      check_writable ("set_name");
349      shdr.sh_name = index;
350      if (!gelf_update_shdr (scn, &shdr))
351        libelf_error ("gelf_update_shdr: " + name_ + " (" + file_->name () + ')');
352    }
353
354    void
355    section::set_reloc_type (bool rela_)
356    {
357      rela = rela_;
358    }
359
360    void
361    section::add (const relocation& reloc)
362    {
363      relocs.push_back (reloc);
364    }
365
366    const relocations&
367    section::get_relocations () const
368    {
369      return relocs;
370    }
371
372    void
373    section::check (const char* where) const
374    {
375      if (!file_ || (index_ < 0) || !scn)
376      {
377        std::string w = where;
378        throw rld::error ("Section not initialised.", "section:check:" + w);
379      }
380    }
381
382    void
383    section::check_writable (const char* where) const
384    {
385      check (where);
386      if (!file_->is_writable ())
387      {
388        std::string w = where;
389        throw rld::error ("File is read-only.", "section:check:");
390      }
391    }
392
393    program_header::program_header ()
394    {
395      memset (&phdr, 0, sizeof (phdr));
396    }
397
398    program_header::~program_header ()
399    {
400    }
401
402    void
403    program_header::set (elf_word type,
404                         elf_word flags,
405                         elf_off offset,
406                         elf_xword filesz,
407                         elf_xword memsz,
408                         elf_xword align,
409                         elf_addr vaddr,
410                         elf_addr paddr)
411    {
412      phdr.p_type = type;
413      phdr.p_flags = flags;
414      phdr.p_offset = offset;
415      phdr.p_vaddr = vaddr;
416      phdr.p_paddr = paddr;
417      phdr.p_filesz = filesz;
418      phdr.p_memsz = memsz;
419      phdr.p_align = align;
420    }
421
422    file::file ()
423      : fd_ (-1),
424        refs (0),
425        archive (false),
426        writable (false),
427        elf_ (0),
428        oclass (0),
429        ident_str (0),
430        ident_size (0),
431        ehdr (0),
432        phdr (0)
433    {
434    }
435
436    file::~file ()
437    {
438      try
439      {
440        end ();
441      }
442      catch (rld::error re)
443      {
444        std::cerr << "error: rld::elf::file::~file: "
445                  << re.where << ": " << re.what
446                  << std::endl;
447      }
448      catch (...)
449      {
450        std::cerr << "error: rld::elf::file::~file: unhandled exception"
451                  << std::endl;
452      }
453    }
454
455    void
456    file::reference_obtain ()
457    {
458      ++refs;
459    }
460
461    void
462    file::reference_release ()
463    {
464      if (refs > 0)
465        --refs;
466    }
467
468    void
469    file::begin (const std::string& name__, int fd__, const bool writable_)
470    {
471      begin (name__, fd__, writable_, 0, 0);
472    }
473
474    void
475    file::begin (const std::string& name__, file& archive_, off_t offset)
476    {
477      archive_.check ("begin:archive");
478
479      if (archive_.writable)
480        throw rld::error ("archive is writable", "elf:file:begin");
481
482      begin (name__, archive_.fd_, false, &archive_, offset);
483    }
484
485    #define rld_archive_fhdr_size (60)
486
487    void
488    file::begin (const std::string& name__,
489                 int                fd__,
490                 const bool         writable_,
491                 file*              archive_,
492                 off_t              offset_)
493    {
494      if (fd__ < 0)
495        throw rld::error ("No file descriptor", "elf:file:begin");
496
497      /*
498       * Begin's are not nesting.
499       */
500      if (elf_ || (fd_ >= 0))
501        throw rld::error ("Already called", "elf:file:begin");
502
503      /*
504       * Cannot write directly into archive. Create a file then archive it.
505       */
506      if (archive_ && writable_)
507        throw rld::error ("Cannot write into archives directly",
508                          "elf:file:begin");
509
510      libelf_initialise ();
511
512      /*
513       * Is this image part of an archive ?
514       */
515      if (archive_)
516      {
517        ssize_t offset = offset_ - rld_archive_fhdr_size;
518        if (::elf_rand (archive_->elf_, offset) != offset)
519          libelf_error ("rand: " + archive_->name_);
520      }
521
522      /*
523       * Note, the elf passed is either the archive or NULL.
524       */
525      elf* elf__ = ::elf_begin (fd__,
526                                writable_ ? ELF_C_WRITE : ELF_C_READ,
527                                archive_ ? archive_->elf_ : 0);
528      if (!elf__)
529        libelf_error ("begin: " + name__);
530
531      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
532        std::cout << "elf::begin: " << elf__ << ' ' << name__ << std::endl;
533
534      elf_kind ek = ::elf_kind (elf__);
535
536      /*
537       * If this is inside an archive it must be an ELF file.
538       */
539
540      if (archive_ && (ek != ELF_K_ELF))
541        throw rld::error ("File format in archive not ELF",
542                          "elf:file:begin: " + name__);
543
544      if (ek == ELF_K_AR)
545        archive = true;
546      else if (ek == ELF_K_ELF)
547        archive = false;
548      else
549        throw rld::error ("File format not ELF or archive",
550                          "elf:file:begin: " + name__);
551
552      if (!writable_)
553      {
554        /*
555         * If an ELF file make sure they all match. On the first file that
556         * begins an ELF session record its settings.
557         */
558        if (ek == ELF_K_ELF)
559        {
560          oclass = ::gelf_getclass (elf__);
561          ident_str = ::elf_getident (elf__, &ident_size);
562        }
563      }
564
565      fd_ = fd__;
566      name_ = name__;
567      writable = writable_;
568      elf_ = elf__;
569
570      if (!archive && !writable)
571      {
572        load_header ();
573        load_sections ();
574      }
575    }
576
577    void
578    file::end ()
579    {
580      if (refs > 0)
581        throw rld::error ("References still held", "elf:file:end: " + name_);
582
583      if (fd_ >= 0)
584      {
585        if (!writable)
586        {
587          if (ehdr)
588          {
589            delete ehdr;
590            ehdr = 0;
591          }
592          if (phdr)
593          {
594            delete phdr;
595            phdr = 0;
596          }
597        }
598
599        fd_ = -1;
600        name_.clear ();
601        archive = false;
602        oclass = 0;
603        ident_str = 0;
604        ident_size = 0;
605        writable = false;
606
607        secs.clear ();
608
609        if (elf_)
610        {
611          if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
612            std::cout << "libelf::end: " << elf_
613                      << ' ' << name_ << std::endl;
614          ::elf_end (elf_);
615          elf_ = 0;
616        }
617      }
618    }
619
620    void
621    file::write ()
622    {
623      check_writable ("write");
624
625      std::string shstrtab;
626
627      for (section_table::iterator sti = secs.begin ();
628           sti != secs.end ();
629           ++sti)
630      {
631        section& sec = (*sti).second;
632        int added_at = shstrtab.size ();
633        shstrtab += '\0' + sec.name ();
634        sec.set_name (added_at + 1);
635      }
636
637      unsigned int shstrtab_name = shstrtab.size () + 1;
638
639      /*
640       * Done this way to clang happy on darwin.
641       */
642      shstrtab += '\0';
643      shstrtab += ".shstrtab";
644
645      /*
646       * Create the string table section.
647       */
648      section shstrsec (*this,
649                        secs.size () + 1,          /* index */
650                        ".shstrtab",               /* name */
651                        SHT_STRTAB,                /* type */
652                        1,                         /* alignment */
653                        SHF_STRINGS | SHF_ALLOC,   /* flags */
654                        0,                         /* address */
655                        0,                         /* offset */
656                        shstrtab.size ());         /* size */
657
658      shstrsec.add_data (ELF_T_BYTE,
659                         1,
660                         shstrtab.size (),
661                         (void*) shstrtab.c_str ());
662
663      shstrsec.set_name (shstrtab_name);
664
665      ::elf_setshstrndx (elf_, shstrsec.index ());
666      ::elf_flagehdr (elf_, ELF_C_SET, ELF_F_DIRTY);
667
668      if (elf_update (elf_, ELF_C_NULL) < 0)
669        libelf_error ("elf_update:layout: " + name_);
670
671      ::elf_flagphdr (elf_, ELF_C_SET, ELF_F_DIRTY);
672
673      if (::elf_update (elf_, ELF_C_WRITE) < 0)
674        libelf_error ("elf_update:write: " + name_);
675    }
676
677    void
678    file::load_header ()
679    {
680      check ("load_header");
681
682      if (!ehdr)
683      {
684        if (!writable)
685          ehdr = new elf_ehdr;
686        else
687        {
688          throw rld::error ("No ELF header; set the header first",
689                            "elf:file:load_header: " + name_);
690        }
691      }
692
693      if (::gelf_getehdr (elf_, ehdr) == 0)
694        error ("gelf_getehdr");
695    }
696
697    unsigned int
698    file::machinetype () const
699    {
700      check_ehdr ("machinetype");
701      return ehdr->e_machine;
702    }
703
704    unsigned int
705    file::type () const
706    {
707      check_ehdr ("type");
708      return ehdr->e_type;
709    }
710
711    unsigned int
712    file::object_class () const
713    {
714      check ("object_class");
715      return oclass;
716    }
717
718    unsigned int
719    file::data_type () const
720    {
721      check ("data_type");
722      if (!ident_str)
723        throw rld::error ("No ELF ident str", "elf:file:data_type: " + name_);
724      return ident_str[EI_DATA];
725    }
726
727    bool
728    file::is_archive () const
729    {
730      check ("is_archive");
731      return archive;
732    }
733
734    bool
735    file::is_executable () const
736    {
737      check_ehdr ("is_executable");
738      return ehdr->e_type != ET_REL;
739    }
740
741    bool
742    file::is_relocatable() const
743    {
744      check_ehdr ("is_relocatable");
745      return ehdr->e_type == ET_REL;
746    }
747
748    int
749    file::section_count () const
750    {
751      check_ehdr ("section_count");
752      return ehdr->e_shnum;
753    }
754
755    void
756    file::load_sections ()
757    {
758      if (secs.empty ())
759      {
760        check ("load_sections_headers");
761        for (int sn = 0; sn < section_count (); ++sn)
762        {
763          section sec (*this, sn);
764          secs[sec.name ()] = sec;
765        }
766      }
767    }
768
769    void
770    file::get_sections (sections& filtered_secs, unsigned int type)
771    {
772      load_sections ();
773      for (section_table::iterator si = secs.begin ();
774           si != secs.end ();
775           ++si)
776      {
777        section& sec = (*si).second;
778        if ((type == 0) || (sec.type () == type))
779          filtered_secs.push_back (&sec);
780      }
781    }
782
783    section&
784    file::get_section (int index)
785    {
786      load_sections ();
787      for (section_table::iterator si = secs.begin ();
788           si != secs.end ();
789           ++si)
790      {
791        section& sec = (*si).second;
792        if (index == sec.index ())
793          return sec;
794      }
795
796      throw rld::error ("section index '" + rld::to_string (index) + "'not found",
797                        "elf:file:get_section: " + name_);
798    }
799
800    int
801    file::strings_section () const
802    {
803      check_ehdr ("strings_sections");
804      return ehdr->e_shstrndx;
805    }
806
807    void
808    file::load_symbols ()
809    {
810      if (symbols.empty ())
811      {
812        if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
813          std::cout << "elf:symbol: " << name () << std::endl;
814
815        sections symbol_secs;
816
817        get_sections (symbol_secs, SHT_SYMTAB);
818
819        for (sections::iterator si = symbol_secs.begin ();
820             si != symbol_secs.end ();
821             ++si)
822        {
823          section& sec = *(*si);
824          int      syms = sec.entries ();
825
826          for (int s = 0; s < syms; ++s)
827          {
828            elf_sym esym;
829
830            if (!::gelf_getsym (sec.data (), s, &esym))
831             error ("gelf_getsym");
832
833            std::string     name = get_string (sec.link (), esym.st_name);
834            symbols::symbol sym (s, name, esym);
835
836            if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
837              std::cout << "elf:symbol: " << sym << std::endl;
838
839            symbols.push_back (sym);
840          }
841        }
842      }
843    }
844
845    void
846    file::get_symbols (symbols::pointers& filtered_syms,
847                       bool               unresolved,
848                       bool               local,
849                       bool               weak,
850                       bool               global)
851    {
852      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
853        std::cout << "elf:get-syms: unresolved:" << unresolved
854                  << " local:" << local
855                  << " weak:" << weak
856                  << " global:" << global
857                  << " " << name_
858                  << std::endl;
859
860      load_symbols ();
861
862      filtered_syms.clear ();
863
864      for (symbols::bucket::iterator si = symbols.begin ();
865           si != symbols.end ();
866           ++si)
867      {
868        symbols::symbol& sym = *si;
869
870        int stype = sym.type ();
871        int sbind = sym.binding ();
872
873        /*
874         * If wanting unresolved symbols and the type is no-type and the
875         * section is undefined, or, the type is no-type or object or function
876         * and the bind is local and we want local symbols, or the bind is weak
877         * and we want weak symbols, or the bind is global and we want global
878         * symbols then add the filtered symbols container.
879         */
880        bool add = false;
881
882        if ((stype == STT_NOTYPE) &&
883            (sbind == STB_GLOBAL) &&
884            (sym.section_index () == SHN_UNDEF))
885        {
886          if (unresolved)
887            add = true;
888        }
889        else
890        {
891          if (((stype == STT_NOTYPE) ||
892               (stype == STT_OBJECT) ||
893               (stype == STT_FUNC)) &&
894              ((weak && (sbind == STB_WEAK)) ||
895               (!unresolved && ((local && (sbind == STB_LOCAL)) ||
896                                (global && (sbind == STB_GLOBAL))))))
897            add = true;
898        }
899
900        if (add)
901          filtered_syms.push_back (&sym);
902      }
903    }
904
905    const symbols::symbol&
906    file::get_symbol (const int index) const
907    {
908      for (symbols::bucket::const_iterator si = symbols.begin ();
909           si != symbols.end ();
910           ++si)
911      {
912        const symbols::symbol& sym = *si;
913        if (index == sym.index ())
914          return sym;
915      }
916
917      throw rld::error ("symbol index '" + rld::to_string (index) + "' not found",
918                        "elf:file:get_symbol: " + name_);
919    }
920
921    void
922    file::load_relocations ()
923    {
924      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
925        std::cout << "elf:reloc: " << name () << std::endl;
926
927      sections rel_secs;
928
929      get_sections (rel_secs, SHT_REL);
930      get_sections (rel_secs, SHT_RELA);
931
932      for (sections::iterator si = rel_secs.begin ();
933           si != rel_secs.end ();
934           ++si)
935      {
936        section& sec = *(*si);
937        section& targetsec = get_section (sec.info ());
938        int      rels = sec.entries ();
939        bool     rela = sec.type () == SHT_RELA;
940
941        targetsec.set_reloc_type (rela);
942
943        if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
944          std::cout << "elf:reloc: " << sec.name ()
945                    << " -> " << targetsec.name ()
946                    << std::endl;
947
948        for (int r = 0; r < rels; ++r)
949        {
950          if (rela)
951          {
952            elf_rela erela;
953
954            if (!::gelf_getrela (sec.data (), r, &erela))
955              error ("gelf_getrela");
956
957            if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
958              std::cout << "elf:reloc: rela: offset: " << erela.r_offset
959                        << " sym:" << GELF_R_SYM (erela.r_info)
960                        << " type:" << GELF_R_TYPE (erela.r_info)
961                        << " addend:" << erela.r_addend
962                        << std::endl;
963
964            /*
965             * The target section is updated with the fix up, and symbol
966             * section indicates the section offset being referenced by the
967             * fixup.
968             */
969
970            const symbols::symbol& sym = get_symbol (GELF_R_SYM (erela.r_info));
971
972            relocation reloc (sym,
973                              erela.r_offset,
974                              erela.r_info,
975                              erela.r_addend);
976
977            targetsec.add (reloc);
978          }
979          else
980          {
981            elf_rel erel;
982
983            if (!::gelf_getrel (sec.data (), r, &erel))
984              error ("gelf_getrel");
985
986            if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
987              std::cout << "elf:reloc: rel: offset: " << erel.r_offset
988                        << " sym:" << GELF_R_SYM (erel.r_info)
989                        << " type:" << GELF_R_TYPE (erel.r_info)
990                        << std::endl;
991
992            const symbols::symbol& sym = get_symbol (GELF_R_SYM (erel.r_info));
993
994            relocation reloc (sym, erel.r_offset, erel.r_info);
995
996            targetsec.add (reloc);
997          }
998        }
999      }
1000    }
1001
1002    std::string
1003    file::get_string (int section, size_t offset)
1004    {
1005      check ("get_string");
1006      char* s = ::elf_strptr (elf_, section, offset);
1007      if (!s)
1008        error ("elf_strptr");
1009      return s;
1010    }
1011
1012    std::string
1013    file::get_string (size_t offset)
1014    {
1015      check ("get_string");
1016      char* s = ::elf_strptr (elf_, strings_section (), offset);
1017      if (!s)
1018        error ("elf_strptr");
1019      return s;
1020    }
1021
1022    void
1023    file::set_header (elf_half      type,
1024                      int           class_,
1025                      elf_half      machinetype,
1026                      unsigned char datatype)
1027    {
1028      check_writable ("set_header");
1029
1030      if (ehdr)
1031          throw rld::error ("ELF header already set",
1032                            "elf:file:set_header: " + name_);
1033
1034      ehdr = (elf_ehdr*) ::gelf_newehdr (elf_, class_);
1035      if (ehdr == 0)
1036        error ("gelf_newehdr");
1037
1038      if (class_ == ELFCLASS32)
1039      {
1040        if((ehdr = (elf_ehdr*) ::elf32_getehdr (elf_)) == 0)
1041          error ("elf32_getehdr");
1042      }
1043      else if (::gelf_getehdr (elf_, ehdr) == 0)
1044        error ("gelf_getehdr");
1045
1046      if (class_ == ELFCLASS32)
1047      {
1048        ((elf32_ehdr*)ehdr)->e_type = type;
1049        ((elf32_ehdr*)ehdr)->e_machine = machinetype;
1050        ((elf32_ehdr*)ehdr)->e_flags = 0;
1051        ((elf32_ehdr*)ehdr)->e_ident[EI_DATA] = datatype;
1052        ((elf32_ehdr*)ehdr)->e_version = EV_CURRENT;
1053      }
1054      else
1055      {
1056        ehdr->e_type = type;
1057        ehdr->e_machine = machinetype;
1058        ehdr->e_flags = 0;
1059        ehdr->e_ident[EI_DATA] = datatype;
1060        ehdr->e_version = EV_CURRENT;
1061      }
1062
1063      ::elf_flagphdr (elf_, ELF_C_SET , ELF_F_DIRTY);
1064    }
1065
1066    void
1067    file::add (section& sec)
1068    {
1069      check_writable ("add");
1070      secs[sec.name ()] = sec;
1071    }
1072
1073    void
1074    file::add (program_header& phdr)
1075    {
1076      check_writable ("add");
1077      phdrs.push_back (phdr);
1078    }
1079
1080    elf*
1081    file::get_elf ()
1082    {
1083      return elf_;
1084    }
1085
1086    const std::string&
1087    file::name () const
1088    {
1089      return name_;
1090    }
1091
1092    bool
1093    file::is_writable () const
1094    {
1095      return writable;
1096    }
1097
1098    size_t
1099    file::machine_size () const
1100    {
1101      size_t bytes;
1102      switch (object_class ())
1103      {
1104      case ELFCLASS64:
1105        bytes = sizeof (uint64_t);
1106        break;
1107      default:
1108        bytes = sizeof (uint32_t);
1109        break;
1110      }
1111      return bytes;
1112    }
1113
1114    bool
1115    file::is_little_endian () const
1116    {
1117      return data_type () == ELFDATA2LSB;
1118    }
1119
1120    void
1121    file::check (const char* where) const
1122    {
1123      if (!elf_ || (fd_ < 0))
1124      {
1125        std::string w = where;
1126        throw rld::error ("No ELF file or file descriptor", "elf:file:" + w);
1127      }
1128    }
1129
1130    void
1131    file::check_ehdr (const char* where) const
1132    {
1133      check (where);
1134      if (!ehdr)
1135      {
1136        std::string w = where;
1137        throw rld::error ("no elf header", "elf:file:" + w);
1138      }
1139    }
1140
1141    void
1142    file::check_phdr (const char* where) const
1143    {
1144      check (where);
1145      if (!phdr)
1146      {
1147        std::string w = where;
1148        throw rld::error ("no elf program header", "elf:file:" + w);
1149      }
1150    }
1151
1152    void
1153    file::check_writable (const char* where) const
1154    {
1155      check (where);
1156      if (!writable)
1157      {
1158        std::string w = where;
1159        throw rld::error ("not writable", "elf:file:" + w);
1160      }
1161    }
1162
1163    void
1164    file::error (const char* where) const
1165    {
1166      std::string w = where;
1167      libelf_error (w + ": " + name_);
1168    }
1169
1170    const std::string
1171    machine_type (unsigned int machinetype)
1172    {
1173      struct types_and_labels
1174      {
1175        const char*  name;        //< The RTEMS label.
1176        unsigned int machinetype; //< The machine type.
1177      };
1178      types_and_labels types_to_labels[] =
1179      {
1180        { "arm",     EM_ARM },
1181        { "avr",     EM_AVR },
1182        { "bfin",    EM_BLACKFIN },
1183        { "h8300",   EM_H8_300 },
1184        { "i386",    EM_386 },
1185     /* { "m32c",    EM_M32C }, Not in libelf I imported */
1186        { "m32r",    EM_M32R },
1187        { "m68k",    EM_68K },
1188        { "m68k",    EM_COLDFIRE },
1189        { "mips",    EM_MIPS },
1190        { "powerpc", EM_PPC },
1191        { "sh",      EM_SH },
1192        { "sparc",   EM_SPARC },
1193        { "sparc64", EM_SPARC },
1194        { 0,         EM_NONE }
1195      };
1196
1197      int m = 0;
1198      while (types_to_labels[m].machinetype != EM_NONE)
1199      {
1200        if (machinetype == types_to_labels[m].machinetype)
1201          return types_to_labels[m].name;
1202        ++m;
1203      }
1204
1205      std::ostringstream what;
1206      what << "unknown machine type: " << elf_object_machinetype;
1207      throw rld::error (what, "machine-type");
1208    }
1209
1210    const std::string
1211    machine_type ()
1212    {
1213      return machine_type (elf_object_machinetype);
1214    }
1215
1216    unsigned int
1217    object_class ()
1218    {
1219      return elf_object_class;
1220    }
1221
1222    unsigned int
1223    object_machine_type ()
1224    {
1225      return elf_object_machinetype;
1226    }
1227
1228    unsigned int
1229    object_datatype ()
1230    {
1231      return elf_object_datatype;
1232    }
1233
1234    void
1235    check_file(const file& file)
1236    {
1237      if (elf_object_machinetype == EM_NONE)
1238        elf_object_machinetype = file.machinetype ();
1239      else if (file.machinetype () != elf_object_machinetype)
1240      {
1241        std::ostringstream oss;
1242        oss << "elf:check_file:" << file.name ()
1243            << ": " << elf_object_machinetype << '/' << file.machinetype ();
1244        throw rld::error ("Mixed machine types not supported.", oss.str ());
1245      }
1246
1247      if (elf_object_class == ELFCLASSNONE)
1248        elf_object_class = file.object_class ();
1249      else if (file.object_class () != elf_object_class)
1250        throw rld::error ("Mixed classes not allowed (32bit/64bit).",
1251                          "elf:check_file: " + file.name ());
1252
1253      if (elf_object_datatype == ELFDATANONE)
1254        elf_object_datatype = file.data_type ();
1255      else if (elf_object_datatype != file.data_type ())
1256        throw rld::error ("Mixed data types not allowed (LSB/MSB).",
1257                          "elf:check_file: " + file.name ());
1258    }
1259
1260  }
1261}
Note: See TracBrowser for help on using the repository browser.