source: rtems-tools/rtemstoolkit/rld-elf.cpp @ 558cab8

5
Last change on this file since 558cab8 was 558cab8, checked in by Chris Johns <chrisj@…>, on 05/08/18 at 05:09:38

rtemstoolkit: Add libdwarf C++ interface.

Provide a C++ interface to libdwarf to:

  • Manage DWARF debug data
  • Manage CU
  • Manage DIE
  • Handle CU line addresses
  • Handle CU source files

Update #3417

  • Property mode set to 100644
File size: 29.5 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      end ();
439    }
440
441    void
442    file::reference_obtain ()
443    {
444      ++refs;
445    }
446
447    void
448    file::reference_release ()
449    {
450      --refs;
451    }
452
453    void
454    file::begin (const std::string& name__, int fd__, const bool writable_)
455    {
456      begin (name__, fd__, writable_, 0, 0);
457    }
458
459    void
460    file::begin (const std::string& name__, file& archive_, off_t offset)
461    {
462      archive_.check ("begin:archive");
463
464      if (archive_.writable)
465        throw rld::error ("archive is writable", "elf:file:begin");
466
467      begin (name__, archive_.fd_, false, &archive_, offset);
468    }
469
470    #define rld_archive_fhdr_size (60)
471
472    void
473    file::begin (const std::string& name__,
474                 int                fd__,
475                 const bool         writable_,
476                 file*              archive_,
477                 off_t              offset_)
478    {
479      if (fd__ < 0)
480        throw rld::error ("No file descriptor", "elf:file:begin");
481
482      /*
483       * Begin's are not nesting.
484       */
485      if (elf_ || (fd_ >= 0))
486        throw rld::error ("Already called", "elf:file:begin");
487
488      /*
489       * Cannot write directly into archive. Create a file then archive it.
490       */
491      if (archive_ && writable_)
492        throw rld::error ("Cannot write into archives directly",
493                          "elf:file:begin");
494
495      libelf_initialise ();
496
497      /*
498       * Is this image part of an archive ?
499       */
500      if (archive_)
501      {
502        ssize_t offset = offset_ - rld_archive_fhdr_size;
503        if (::elf_rand (archive_->elf_, offset) != offset)
504          libelf_error ("rand: " + archive_->name_);
505      }
506
507      /*
508       * Note, the elf passed is either the archive or NULL.
509       */
510      elf* elf__ = ::elf_begin (fd__,
511                                writable_ ? ELF_C_WRITE : ELF_C_READ,
512                                archive_ ? archive_->elf_ : 0);
513      if (!elf__)
514        libelf_error ("begin: " + name__);
515
516      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
517        std::cout << "elf::begin: " << elf__ << ' ' << name__ << std::endl;
518
519      elf_kind ek = ::elf_kind (elf__);
520
521      /*
522       * If this is inside an archive it must be an ELF file.
523       */
524
525      if (archive_ && (ek != ELF_K_ELF))
526        throw rld::error ("File format in archive not ELF",
527                          "elf:file:begin: " + name__);
528      else
529      {
530        if (ek == ELF_K_AR)
531          archive = true;
532        else if (ek == ELF_K_ELF)
533          archive = false;
534        else
535          throw rld::error ("File format not ELF or archive",
536                            "elf:file:begin: " + name__);
537      }
538
539      if (!writable_)
540      {
541        /*
542         * If an ELF file make sure they all match. On the first file that
543         * begins an ELF session record its settings.
544         */
545        if (ek == ELF_K_ELF)
546        {
547          oclass = ::gelf_getclass (elf__);
548          ident_str = elf_getident (elf__, &ident_size);
549        }
550      }
551
552      fd_ = fd__;
553      name_ = name__;
554      writable = writable_;
555      elf_ = elf__;
556
557      if (!archive && !writable)
558      {
559        load_header ();
560        load_sections ();
561      }
562    }
563
564    void
565    file::end ()
566    {
567      if (refs > 0)
568        throw rld::error ("References still held", "elf:file:end: " + name_);
569
570      if (elf_)
571      {
572        if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
573          std::cout << "libelf::end: " << elf_
574                    << ' ' << name_ << std::endl;
575        ::elf_end (elf_);
576        elf_ = 0;
577      }
578
579      if (fd_ >= 0)
580      {
581        if (!writable)
582        {
583          if (ehdr)
584          {
585            delete ehdr;
586            ehdr = 0;
587          }
588          if (phdr)
589          {
590            delete phdr;
591            phdr = 0;
592          }
593        }
594
595        fd_ = -1;
596        name_.clear ();
597        archive = false;
598        elf_ = 0;
599        oclass = 0;
600        ident_str = 0;
601        ident_size = 0;
602        writable = false;
603        secs.clear ();
604      }
605    }
606
607    void
608    file::write ()
609    {
610      check_writable ("write");
611
612      std::string shstrtab;
613
614      for (section_table::iterator sti = secs.begin ();
615           sti != secs.end ();
616           ++sti)
617      {
618        section& sec = (*sti).second;
619        int added_at = shstrtab.size ();
620        shstrtab += '\0' + sec.name ();
621        sec.set_name (added_at + 1);
622      }
623
624      unsigned int shstrtab_name = shstrtab.size () + 1;
625
626      /*
627       * Done this way to clang happy on darwin.
628       */
629      shstrtab += '\0';
630      shstrtab += ".shstrtab";
631
632      /*
633       * Create the string table section.
634       */
635      section shstrsec (*this,
636                        secs.size () + 1,          /* index */
637                        ".shstrtab",               /* name */
638                        SHT_STRTAB,                /* type */
639                        1,                         /* alignment */
640                        SHF_STRINGS | SHF_ALLOC,   /* flags */
641                        0,                         /* address */
642                        0,                         /* offset */
643                        shstrtab.size ());         /* size */
644
645      shstrsec.add_data (ELF_T_BYTE,
646                         1,
647                         shstrtab.size (),
648                         (void*) shstrtab.c_str ());
649
650      shstrsec.set_name (shstrtab_name);
651
652      ::elf_setshstrndx (elf_, shstrsec.index ());
653      ::elf_flagehdr (elf_, ELF_C_SET, ELF_F_DIRTY);
654
655      if (elf_update (elf_, ELF_C_NULL) < 0)
656        libelf_error ("elf_update:layout: " + name_);
657
658      ::elf_flagphdr (elf_, ELF_C_SET, ELF_F_DIRTY);
659
660      if (::elf_update (elf_, ELF_C_WRITE) < 0)
661        libelf_error ("elf_update:write: " + name_);
662    }
663
664    void
665    file::load_header ()
666    {
667      check ("load_header");
668
669      if (!ehdr)
670      {
671        if (!writable)
672          ehdr = new elf_ehdr;
673        else
674        {
675          throw rld::error ("No ELF header; set the header first",
676                            "elf:file:load_header: " + name_);
677        }
678      }
679
680      if (::gelf_getehdr (elf_, ehdr) == 0)
681        error ("gelf_getehdr");
682    }
683
684    unsigned int
685    file::machinetype () const
686    {
687      check_ehdr ("machinetype");
688      return ehdr->e_machine;
689    }
690
691    unsigned int
692    file::type () const
693    {
694      check_ehdr ("type");
695      return ehdr->e_type;
696    }
697
698    unsigned int
699    file::object_class () const
700    {
701      check ("object_class");
702      return oclass;
703    }
704
705    unsigned int
706    file::data_type () const
707    {
708      check ("data_type");
709      if (!ident_str)
710        throw rld::error ("No ELF ident str", "elf:file:data_type: " + name_);
711      return ident_str[EI_DATA];
712    }
713
714    bool
715    file::is_archive () const
716    {
717      check ("is_archive");
718      return archive;
719    }
720
721    bool
722    file::is_executable () const
723    {
724      check_ehdr ("is_executable");
725      return ehdr->e_type != ET_REL;
726    }
727
728    bool
729    file::is_relocatable() const
730    {
731      check_ehdr ("is_relocatable");
732      return ehdr->e_type == ET_REL;
733    }
734
735    int
736    file::section_count () const
737    {
738      check_ehdr ("section_count");
739      return ehdr->e_shnum;
740    }
741
742    void
743    file::load_sections ()
744    {
745      if (secs.empty ())
746      {
747        check ("load_sections_headers");
748        for (int sn = 0; sn < section_count (); ++sn)
749        {
750          section sec (*this, sn);
751          secs[sec.name ()] = sec;
752        }
753      }
754    }
755
756    void
757    file::get_sections (sections& filtered_secs, unsigned int type)
758    {
759      load_sections ();
760      for (section_table::iterator si = secs.begin ();
761           si != secs.end ();
762           ++si)
763      {
764        section& sec = (*si).second;
765        if ((type == 0) || (sec.type () == type))
766          filtered_secs.push_back (&sec);
767      }
768    }
769
770    section&
771    file::get_section (int index)
772    {
773      load_sections ();
774      for (section_table::iterator si = secs.begin ();
775           si != secs.end ();
776           ++si)
777      {
778        section& sec = (*si).second;
779        if (index == sec.index ())
780          return sec;
781      }
782
783      throw rld::error ("section index '" + rld::to_string (index) + "'not found",
784                        "elf:file:get_section: " + name_);
785    }
786
787    int
788    file::strings_section () const
789    {
790      check_ehdr ("strings_sections");
791      return ehdr->e_shstrndx;
792    }
793
794    void
795    file::load_symbols ()
796    {
797      if (symbols.empty ())
798      {
799        if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
800          std::cout << "elf:symbol: " << name () << std::endl;
801
802        sections symbol_secs;
803
804        get_sections (symbol_secs, SHT_SYMTAB);
805
806        for (sections::iterator si = symbol_secs.begin ();
807             si != symbol_secs.end ();
808             ++si)
809        {
810          section& sec = *(*si);
811          int      syms = sec.entries ();
812
813          for (int s = 0; s < syms; ++s)
814          {
815            elf_sym esym;
816
817            if (!::gelf_getsym (sec.data (), s, &esym))
818             error ("gelf_getsym");
819
820            std::string     name = get_string (sec.link (), esym.st_name);
821            symbols::symbol sym (s, name, esym);
822
823            if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
824              std::cout << "elf:symbol: " << sym << std::endl;
825
826            symbols.push_back (sym);
827          }
828        }
829      }
830    }
831
832    void
833    file::get_symbols (symbols::pointers& filtered_syms,
834                       bool               unresolved,
835                       bool               local,
836                       bool               weak,
837                       bool               global)
838    {
839      if (rld::verbose () >= RLD_VERBOSE_TRACE_SYMS)
840        std::cout << "elf:get-syms: unresolved:" << unresolved
841                  << " local:" << local
842                  << " weak:" << weak
843                  << " global:" << global
844                  << " " << name_
845                  << std::endl;
846
847      load_symbols ();
848
849      filtered_syms.clear ();
850
851      for (symbols::bucket::iterator si = symbols.begin ();
852           si != symbols.end ();
853           ++si)
854      {
855        symbols::symbol& sym = *si;
856
857        int stype = sym.type ();
858        int sbind = sym.binding ();
859
860        /*
861         * If wanting unresolved symbols and the type is no-type and the
862         * section is undefined, or, the type is no-type or object or function
863         * and the bind is local and we want local symbols, or the bind is weak
864         * and we want weak symbols, or the bind is global and we want global
865         * symbols then add the filtered symbols container.
866         */
867        bool add = false;
868
869        if ((stype == STT_NOTYPE) &&
870            (sbind == STB_GLOBAL) &&
871            (sym.section_index () == SHN_UNDEF))
872        {
873          if (unresolved)
874            add = true;
875        }
876        else
877        {
878          if (((stype == STT_NOTYPE) ||
879               (stype == STT_OBJECT) ||
880               (stype == STT_FUNC)) &&
881              ((weak && (sbind == STB_WEAK)) ||
882               (!unresolved && ((local && (sbind == STB_LOCAL)) ||
883                                (global && (sbind == STB_GLOBAL))))))
884            add = true;
885        }
886
887        if (add)
888          filtered_syms.push_back (&sym);
889      }
890    }
891
892    const symbols::symbol&
893    file::get_symbol (const int index) const
894    {
895      for (symbols::bucket::const_iterator si = symbols.begin ();
896           si != symbols.end ();
897           ++si)
898      {
899        const symbols::symbol& sym = *si;
900        if (index == sym.index ())
901          return sym;
902      }
903
904      throw rld::error ("symbol index '" + rld::to_string (index) + "' not found",
905                        "elf:file:get_symbol: " + name_);
906    }
907
908    void
909    file::load_relocations ()
910    {
911      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
912        std::cout << "elf:reloc: " << name () << std::endl;
913
914      sections rel_secs;
915
916      get_sections (rel_secs, SHT_REL);
917      get_sections (rel_secs, SHT_RELA);
918
919      for (sections::iterator si = rel_secs.begin ();
920           si != rel_secs.end ();
921           ++si)
922      {
923        section& sec = *(*si);
924        section& targetsec = get_section (sec.info ());
925        int      rels = sec.entries ();
926        bool     rela = sec.type () == SHT_RELA;
927
928        targetsec.set_reloc_type (rela);
929
930        if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
931          std::cout << "elf:reloc: " << sec.name ()
932                    << " -> " << targetsec.name ()
933                    << std::endl;
934
935        for (int r = 0; r < rels; ++r)
936        {
937          if (rela)
938          {
939            elf_rela erela;
940
941            if (!::gelf_getrela (sec.data (), r, &erela))
942              error ("gelf_getrela");
943
944            if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
945              std::cout << "elf:reloc: rela: offset: " << erela.r_offset
946                        << " sym:" << GELF_R_SYM (erela.r_info)
947                        << " type:" << GELF_R_TYPE (erela.r_info)
948                        << " addend:" << erela.r_addend
949                        << std::endl;
950
951            /*
952             * The target section is updated with the fix up, and symbol
953             * section indicates the section offset being referenced by the
954             * fixup.
955             */
956
957            const symbols::symbol& sym = get_symbol (GELF_R_SYM (erela.r_info));
958
959            relocation reloc (sym,
960                              erela.r_offset,
961                              erela.r_info,
962                              erela.r_addend);
963
964            targetsec.add (reloc);
965          }
966          else
967          {
968            elf_rel erel;
969
970            if (!::gelf_getrel (sec.data (), r, &erel))
971              error ("gelf_getrel");
972
973            if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
974              std::cout << "elf:reloc: rel: offset: " << erel.r_offset
975                        << " sym:" << GELF_R_SYM (erel.r_info)
976                        << " type:" << GELF_R_TYPE (erel.r_info)
977                        << std::endl;
978
979            const symbols::symbol& sym = get_symbol (GELF_R_SYM (erel.r_info));
980
981            relocation reloc (sym, erel.r_offset, erel.r_info);
982
983            targetsec.add (reloc);
984          }
985        }
986      }
987    }
988
989    std::string
990    file::get_string (int section, size_t offset)
991    {
992      check ("get_string");
993      char* s = ::elf_strptr (elf_, section, offset);
994      if (!s)
995        error ("elf_strptr");
996      return s;
997    }
998
999    std::string
1000    file::get_string (size_t offset)
1001    {
1002      check ("get_string");
1003      char* s = ::elf_strptr (elf_, strings_section (), offset);
1004      if (!s)
1005        error ("elf_strptr");
1006      return s;
1007    }
1008
1009    void
1010    file::set_header (elf_half      type,
1011                      int           class_,
1012                      elf_half      machinetype,
1013                      unsigned char datatype)
1014    {
1015      check_writable ("set_header");
1016
1017      if (ehdr)
1018          throw rld::error ("ELF header already set",
1019                            "elf:file:set_header: " + name_);
1020
1021      ehdr = (elf_ehdr*) ::gelf_newehdr (elf_, class_);
1022      if (ehdr == 0)
1023        error ("gelf_newehdr");
1024
1025      if (class_ == ELFCLASS32)
1026      {
1027        if((ehdr = (elf_ehdr*) ::elf32_getehdr (elf_)) == 0)
1028          error ("elf32_getehdr");
1029      }
1030      else if (::gelf_getehdr (elf_, ehdr) == 0)
1031        error ("gelf_getehdr");
1032
1033      if (class_ == ELFCLASS32)
1034      {
1035        ((elf32_ehdr*)ehdr)->e_type = type;
1036        ((elf32_ehdr*)ehdr)->e_machine = machinetype;
1037        ((elf32_ehdr*)ehdr)->e_flags = 0;
1038        ((elf32_ehdr*)ehdr)->e_ident[EI_DATA] = datatype;
1039        ((elf32_ehdr*)ehdr)->e_version = EV_CURRENT;
1040      }
1041      else
1042      {
1043        ehdr->e_type = type;
1044        ehdr->e_machine = machinetype;
1045        ehdr->e_flags = 0;
1046        ehdr->e_ident[EI_DATA] = datatype;
1047        ehdr->e_version = EV_CURRENT;
1048      }
1049
1050      ::elf_flagphdr (elf_, ELF_C_SET , ELF_F_DIRTY);
1051    }
1052
1053    void
1054    file::add (section& sec)
1055    {
1056      check_writable ("add");
1057      secs[sec.name ()] = sec;
1058    }
1059
1060    void
1061    file::add (program_header& phdr)
1062    {
1063      check_writable ("add");
1064      phdrs.push_back (phdr);
1065    }
1066
1067    elf*
1068    file::get_elf ()
1069    {
1070      return elf_;
1071    }
1072
1073    const std::string&
1074    file::name () const
1075    {
1076      return name_;
1077    }
1078
1079    bool
1080    file::is_writable () const
1081    {
1082      return writable;
1083    }
1084
1085    void
1086    file::check (const char* where) const
1087    {
1088      if (!elf_ || (fd_ < 0))
1089      {
1090        std::string w = where;
1091        throw rld::error ("No ELF file or file descriptor", "elf:file:" + w);
1092      }
1093    }
1094
1095    void
1096    file::check_ehdr (const char* where) const
1097    {
1098      check (where);
1099      if (!ehdr)
1100      {
1101        std::string w = where;
1102        throw rld::error ("no elf header", "elf:file:" + w);
1103      }
1104    }
1105
1106    void
1107    file::check_phdr (const char* where) const
1108    {
1109      check (where);
1110      if (!phdr)
1111      {
1112        std::string w = where;
1113        throw rld::error ("no elf program header", "elf:file:" + w);
1114      }
1115    }
1116
1117    void
1118    file::check_writable (const char* where) const
1119    {
1120      check (where);
1121      if (!writable)
1122      {
1123        std::string w = where;
1124        throw rld::error ("not writable", "elf:file:" + w);
1125      }
1126    }
1127
1128    void
1129    file::error (const char* where) const
1130    {
1131      std::string w = where;
1132      libelf_error (w + ": " + name_);
1133    }
1134
1135    const std::string
1136    machine_type (unsigned int machinetype)
1137    {
1138      struct types_and_labels
1139      {
1140        const char*  name;        //< The RTEMS label.
1141        unsigned int machinetype; //< The machine type.
1142      };
1143      types_and_labels types_to_labels[] =
1144      {
1145        { "arm",     EM_ARM },
1146        { "avr",     EM_AVR },
1147        { "bfin",    EM_BLACKFIN },
1148        { "h8300",   EM_H8_300 },
1149        { "i386",    EM_386 },
1150     /* { "m32c",    EM_M32C }, Not in libelf I imported */
1151        { "m32r",    EM_M32R },
1152        { "m68k",    EM_68K },
1153        { "m68k",    EM_COLDFIRE },
1154        { "mips",    EM_MIPS },
1155        { "powerpc", EM_PPC },
1156        { "sh",      EM_SH },
1157        { "sparc",   EM_SPARC },
1158        { "sparc64", EM_SPARC },
1159        { 0,         EM_NONE }
1160      };
1161
1162      int m = 0;
1163      while (types_to_labels[m].machinetype != EM_NONE)
1164      {
1165        if (machinetype == types_to_labels[m].machinetype)
1166          return types_to_labels[m].name;
1167        ++m;
1168      }
1169
1170      std::ostringstream what;
1171      what << "unknown machine type: " << elf_object_machinetype;
1172      throw rld::error (what, "machine-type");
1173    }
1174
1175    const std::string
1176    machine_type ()
1177    {
1178      return machine_type (elf_object_machinetype);
1179    }
1180
1181    unsigned int
1182    object_class ()
1183    {
1184      return elf_object_class;
1185    }
1186
1187    unsigned int
1188    object_machine_type ()
1189    {
1190      return elf_object_machinetype;
1191    }
1192
1193    unsigned int
1194    object_datatype ()
1195    {
1196      return elf_object_datatype;
1197    }
1198
1199    void
1200    check_file(const file& file)
1201    {
1202      if (elf_object_machinetype == EM_NONE)
1203        elf_object_machinetype = file.machinetype ();
1204      else if (file.machinetype () != elf_object_machinetype)
1205      {
1206        std::ostringstream oss;
1207        oss << "elf:check_file:" << file.name ()
1208            << ": " << elf_object_machinetype << '/' << file.machinetype ();
1209        throw rld::error ("Mixed machine types not supported.", oss.str ());
1210      }
1211
1212      if (elf_object_class == ELFCLASSNONE)
1213        elf_object_class = file.object_class ();
1214      else if (file.object_class () != elf_object_class)
1215        throw rld::error ("Mixed classes not allowed (32bit/64bit).",
1216                          "elf:check_file: " + file.name ());
1217
1218      if (elf_object_datatype == ELFDATANONE)
1219        elf_object_datatype = file.data_type ();
1220      else if (elf_object_datatype != file.data_type ())
1221        throw rld::error ("Mixed data types not allowed (LSB/MSB).",
1222                          "elf:check_file: " + file.name ());
1223    }
1224
1225  }
1226}
Note: See TracBrowser for help on using the repository browser.