build/unix/elfhack/elfxx.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "mozilla/NullPtr.h"
     7 #include <stdexcept>
     8 #include <list>
     9 #include <vector>
    10 #include <cstring>
    11 #include <iostream>
    12 #include <fstream>
    13 #include <algorithm>
    14 #include <elf.h>
    15 #include <asm/byteorder.h>
    17 // Technically, __*_to_cpu and __cpu_to* function are equivalent,
    18 // so swap can use either of both.
    19 #define def_swap(endian, type, bits) \
    20 static inline type ## bits ## _t swap(type ## bits ## _t i) { \
    21     return __ ## endian ## bits ## _to_cpu(i); \
    22 }
    24 class little_endian {
    25 public:
    26 def_swap(le, uint, 16);
    27 def_swap(le, uint, 32);
    28 def_swap(le, uint, 64);
    29 def_swap(le, int, 16);
    30 def_swap(le, int, 32);
    31 def_swap(le, int, 64);
    32 };
    34 class big_endian {
    35 public:
    36 def_swap(be, uint, 16);
    37 def_swap(be, uint, 32);
    38 def_swap(be, uint, 64);
    39 def_swap(be, int, 16);
    40 def_swap(be, int, 32);
    41 def_swap(be, int, 64);
    42 };
    44 // forward declaration
    45 class ElfSection;
    46 class ElfSegment;
    47 // TODO: Rename Elf_* types
    48 class Elf_Ehdr;
    49 class Elf_Phdr;
    50 class Elf;
    51 class ElfDynamic_Section;
    52 class ElfStrtab_Section;
    54 class Elf_Ehdr_Traits {
    55 public:
    56     typedef Elf32_Ehdr Type32;
    57     typedef Elf64_Ehdr Type64;
    59     template <class endian, typename R, typename T>
    60     static void swap(T &t, R &r);
    61 };
    63 class Elf_Phdr_Traits {
    64 public:
    65     typedef Elf32_Phdr Type32;
    66     typedef Elf64_Phdr Type64;
    68     template <class endian, typename R, typename T>
    69     static void swap(T &t, R &r);
    70 };
    72 class Elf_Shdr_Traits {
    73 public:
    74     typedef Elf32_Shdr Type32;
    75     typedef Elf64_Shdr Type64;
    77     template <class endian, typename R, typename T>
    78     static void swap(T &t, R &r);
    79 };
    81 class Elf_Dyn_Traits {
    82 public:
    83     typedef Elf32_Dyn Type32;
    84     typedef Elf64_Dyn Type64;
    86     template <class endian, typename R, typename T>
    87     static void swap(T &t, R &r);
    88 };
    90 class Elf_Sym_Traits {
    91 public:
    92     typedef Elf32_Sym Type32;
    93     typedef Elf64_Sym Type64;
    95     template <class endian, typename R, typename T>
    96     static void swap(T &t, R &r);
    97 };
    99 class Elf_Rel_Traits {
   100 public:
   101     typedef Elf32_Rel Type32;
   102     typedef Elf64_Rel Type64;
   104     template <class endian, typename R, typename T>
   105     static void swap(T &t, R &r);
   106 };
   108 class Elf_Rela_Traits {
   109 public:
   110     typedef Elf32_Rela Type32;
   111     typedef Elf64_Rela Type64;
   113     template <class endian, typename R, typename T>
   114     static void swap(T &t, R &r);
   115 };
   117 class ElfValue {
   118 public:
   119     virtual unsigned int getValue() { return 0; }
   120     virtual ElfSection *getSection() { return nullptr; }
   121 };
   123 class ElfPlainValue: public ElfValue {
   124     unsigned int value;
   125 public:
   126     ElfPlainValue(unsigned int val): value(val) {};
   127     unsigned int getValue() { return value; }
   128 };
   130 class ElfLocation: public ElfValue {
   131     ElfSection *section;
   132     unsigned int offset;
   133 public:
   134     enum position { ABSOLUTE, RELATIVE };
   135     ElfLocation(): section(nullptr), offset(0) {};
   136     ElfLocation(ElfSection *section, unsigned int off, enum position pos = RELATIVE);
   137     ElfLocation(unsigned int location, Elf *elf);
   138     unsigned int getValue();
   139     ElfSection *getSection() { return section; }
   140     const char *getBuffer();
   141 };
   143 class ElfSize: public ElfValue {
   144     ElfSection *section;
   145 public:
   146     ElfSize(ElfSection *s): section(s) {};
   147     unsigned int getValue();
   148     ElfSection *getSection() { return section; }
   149 };
   151 class ElfEntSize: public ElfValue {
   152     ElfSection *section;
   153 public:
   154     ElfEntSize(ElfSection *s): section(s) {};
   155     unsigned int getValue();
   156     ElfSection *getSection() { return section; }
   157 };
   159 template <typename T>
   160 class serializable: public T::Type32 {
   161 public:
   162     serializable() {};
   163     serializable(const typename T::Type32 &p): T::Type32(p) {};
   165 private:
   166     template <typename R>
   167     void init(const char *buf, size_t len, char ei_data)
   168     {
   169         R e;
   170         assert(len >= sizeof(e));
   171         memcpy(&e, buf, sizeof(e));
   172         if (ei_data == ELFDATA2LSB) {
   173             T::template swap<little_endian>(e, *this);
   174             return;
   175         } else if (ei_data == ELFDATA2MSB) {
   176             T::template swap<big_endian>(e, *this);
   177             return;
   178         }
   179         throw std::runtime_error("Unsupported ELF data encoding");
   180     }
   182     template <typename R>
   183     void serialize(const char *buf, size_t len, char ei_data)
   184     {
   185         assert(len >= sizeof(R));
   186         if (ei_data == ELFDATA2LSB) {
   187             T::template swap<little_endian>(*this, *(R *)buf);
   188             return;
   189         } else if (ei_data == ELFDATA2MSB) {
   190             T::template swap<big_endian>(*this, *(R *)buf);
   191             return;
   192         }
   193         throw std::runtime_error("Unsupported ELF data encoding");
   194     }
   196 public:
   197     serializable(const char *buf, size_t len, char ei_class, char ei_data)
   198     {
   199         if (ei_class == ELFCLASS32) {
   200             init<typename T::Type32>(buf, len, ei_data);
   201             return;
   202         } else if (ei_class == ELFCLASS64) {
   203             init<typename T::Type64>(buf, len, ei_data);
   204             return;
   205         }
   206         throw std::runtime_error("Unsupported ELF class");
   207     }
   209     serializable(std::ifstream &file, char ei_class, char ei_data)
   210     {
   211         if (ei_class == ELFCLASS32) {
   212             typename T::Type32 e;
   213             file.read((char *)&e, sizeof(e));
   214             init<typename T::Type32>((char *)&e, sizeof(e), ei_data);
   215             return;
   216         } else if (ei_class == ELFCLASS64) {
   217             typename T::Type64 e;
   218             file.read((char *)&e, sizeof(e));
   219             init<typename T::Type64>((char *)&e, sizeof(e), ei_data);
   220             return;
   221         }
   222         throw std::runtime_error("Unsupported ELF class or data encoding");
   223     }
   225     void serialize(std::ofstream &file, char ei_class, char ei_data)
   226     {
   227         if (ei_class == ELFCLASS32) {
   228             typename T::Type32 e;
   229             serialize<typename T::Type32>((char *)&e, sizeof(e), ei_data);
   230             file.write((char *)&e, sizeof(e));
   231             return;
   232         } else if (ei_class == ELFCLASS64) {
   233             typename T::Type64 e;
   234             serialize<typename T::Type64>((char *)&e, sizeof(e), ei_data);
   235             file.write((char *)&e, sizeof(e));
   236             return;
   237         }
   238         throw std::runtime_error("Unsupported ELF class or data encoding");
   239     }
   241     void serialize(char *buf, size_t len, char ei_class, char ei_data)
   242     {
   243         if (ei_class == ELFCLASS32) {
   244             serialize<typename T::Type32>(buf, len, ei_data);
   245             return;
   246         } else if (ei_class == ELFCLASS64) {
   247             serialize<typename T::Type64>(buf, len, ei_data);
   248             return;
   249         }
   250         throw std::runtime_error("Unsupported ELF class");
   251     }
   253     static inline unsigned int size(char ei_class)
   254     {
   255         if (ei_class == ELFCLASS32)
   256             return sizeof(typename T::Type32);
   257         else if (ei_class == ELFCLASS64)
   258             return sizeof(typename T::Type64);
   259         return 0;
   260     }
   261 };
   263 typedef serializable<Elf_Shdr_Traits> Elf_Shdr;
   265 class Elf {
   266 public:
   267     Elf(std::ifstream &file);
   268     ~Elf();
   270     /* index == -1 is treated as index == ehdr.e_shstrndx */
   271     ElfSection *getSection(int index);
   273     ElfSection *getSectionAt(unsigned int offset);
   275     ElfSegment *getSegmentByType(unsigned int type, ElfSegment *last = nullptr);
   277     ElfDynamic_Section *getDynSection();
   279     void normalize();
   280     void write(std::ofstream &file);
   282     char getClass();
   283     char getData();
   284     char getType();
   285     char getMachine();
   286     unsigned int getSize();
   288     void insertSegmentAfter(ElfSegment *previous, ElfSegment *segment) {
   289         std::vector<ElfSegment *>::iterator prev = std::find(segments.begin(), segments.end(), previous);
   290         segments.insert(prev + 1, segment);
   291     }
   293     void removeSegment(ElfSegment *segment);
   295 private:
   296     Elf_Ehdr *ehdr;
   297     ElfLocation eh_entry;
   298     ElfStrtab_Section *eh_shstrndx;
   299     ElfSection **sections;
   300     std::vector<ElfSegment *> segments;
   301     ElfSection *shdr_section, *phdr_section;
   302     /* Values used only during initialization */
   303     Elf_Shdr **tmp_shdr;
   304     std::ifstream *tmp_file;
   305 };
   307 class ElfSection {
   308 public:
   309     typedef union {
   310         ElfSection *section;
   311         int index;
   312     } SectionInfo;
   314     ElfSection(Elf_Shdr &s, std::ifstream *file, Elf *parent);
   316     virtual ~ElfSection() {
   317         delete[] data;
   318     }
   320     const char *getName() { return name; }
   321     unsigned int getType() { return shdr.sh_type; }
   322     unsigned int getFlags() { return shdr.sh_flags; }
   323     unsigned int getAddr();
   324     unsigned int getSize() { return shdr.sh_size; }
   325     unsigned int getAddrAlign() { return shdr.sh_addralign; }
   326     unsigned int getEntSize() { return shdr.sh_entsize; }
   327     const char *getData() { return data; }
   328     ElfSection *getLink() { return link; }
   329     SectionInfo getInfo() { return info; }
   331     void shrink(unsigned int newsize) {
   332         if (newsize < shdr.sh_size)
   333             shdr.sh_size = newsize;
   334     }
   336     unsigned int getOffset();
   337     int getIndex();
   338     Elf_Shdr &getShdr();
   340     ElfSection *getNext() { return next; }
   341     ElfSection *getPrevious() { return previous; }
   343     virtual bool isRelocatable() {
   344         return ((getType() == SHT_SYMTAB) ||
   345                 (getType() == SHT_STRTAB) ||
   346                 (getType() == SHT_RELA) ||
   347                 (getType() == SHT_HASH) ||
   348                 (getType() == SHT_NOTE) ||
   349                 (getType() == SHT_REL) ||
   350                 (getType() == SHT_DYNSYM) ||
   351                 (getType() == SHT_GNU_HASH) ||
   352                 (getType() == SHT_GNU_verdef) ||
   353                 (getType() == SHT_GNU_verneed) ||
   354                 (getType() == SHT_GNU_versym) ||
   355                 getSegmentByType(PT_INTERP)) &&
   356                 (getFlags() & SHF_ALLOC);
   357     }
   359     void insertAfter(ElfSection *section, bool dirty = true) {
   360         if (previous != nullptr)
   361             previous->next = next;
   362         if (next != nullptr)
   363             next->previous = previous;
   364         previous = section;
   365         if (section != nullptr) {
   366             next = section->next;
   367             section->next = this;
   368         } else
   369             next = nullptr;
   370         if (next != nullptr)
   371             next->previous = this;
   372         if (dirty)
   373             markDirty();
   374         insertInSegments(section->segments);
   375     }
   377     void insertBefore(ElfSection *section, bool dirty = true) {
   378         if (previous != nullptr)
   379             previous->next = next;
   380         if (next != nullptr)
   381             next->previous = previous;
   382         next = section;
   383         if (section != nullptr) {
   384             previous = section->previous;
   385             section->previous = this;
   386         } else
   387             previous = nullptr;
   388         if (previous != nullptr)
   389             previous->next = this;
   390         if (dirty)
   391             markDirty();
   392         insertInSegments(section->segments);
   393     }
   395     void markDirty() {
   396         if (link != nullptr)
   397             shdr.sh_link = -1;
   398         if (info.index)
   399             shdr.sh_info = -1;
   400         shdr.sh_offset = -1;
   401         if (isRelocatable())
   402             shdr.sh_addr = -1;
   403         if (next)
   404             next->markDirty();
   405     }
   407     virtual void serialize(std::ofstream &file, char ei_class, char ei_data)
   408     {
   409         if (getType() == SHT_NOBITS)
   410             return;
   411         file.seekp(getOffset());
   412         file.write(data, getSize());
   413     }
   415 private:
   416     friend class ElfSegment;
   418     void addToSegment(ElfSegment *segment) {
   419         segments.push_back(segment);
   420     }
   422     void removeFromSegment(ElfSegment *segment) {
   423         std::vector<ElfSegment *>::iterator i = std::find(segments.begin(), segments.end(), segment);
   424         segments.erase(i, i + 1);
   425     }
   427     ElfSegment *getSegmentByType(unsigned int type);
   429     void insertInSegments(std::vector<ElfSegment *> &segs);
   431 protected:
   432     Elf_Shdr shdr;
   433     char *data;
   434     const char *name;
   435 private:
   436     ElfSection *link;
   437     SectionInfo info;
   438     ElfSection *next, *previous;
   439     int index;
   440     std::vector<ElfSegment *> segments;
   441 };
   443 class ElfSegment {
   444 public:
   445     ElfSegment(Elf_Phdr *phdr);
   447     unsigned int getType() { return type; }
   448     unsigned int getFlags() { return flags; }
   449     unsigned int getAlign() { return align; }
   451     ElfSection *getFirstSection() { return sections.empty() ? nullptr : sections.front(); }
   452     int getVPDiff() { return v_p_diff; }
   453     unsigned int getFileSize();
   454     unsigned int getMemSize();
   455     unsigned int getOffset();
   456     unsigned int getAddr();
   458     void addSection(ElfSection *section);
   459     void removeSection(ElfSection *section);
   461     std::list<ElfSection *>::iterator begin() { return sections.begin(); }
   462     std::list<ElfSection *>::iterator end() { return sections.end(); }
   464     void clear();
   466     bool isElfHackFillerSegment() {
   467       return type == PT_LOAD && flags == 0;
   468     }
   469 private:
   470     unsigned int type;
   471     int v_p_diff; // Difference between physical and virtual address
   472     unsigned int flags;
   473     unsigned int align;
   474     std::list<ElfSection *> sections;
   475     // The following are only really used for PT_GNU_RELRO until something
   476     // better is found.
   477     unsigned int vaddr;
   478     unsigned int filesz, memsz;
   479 };
   481 class Elf_Ehdr: public serializable<Elf_Ehdr_Traits>, public ElfSection {
   482 public:
   483     Elf_Ehdr(std::ifstream &file, char ei_class, char ei_data);
   484     void serialize(std::ofstream &file, char ei_class, char ei_data)
   485     {
   486         serializable<Elf_Ehdr_Traits>::serialize(file, ei_class, ei_data);
   487     }
   488 };
   490 class Elf_Phdr: public serializable<Elf_Phdr_Traits> {
   491 public:
   492     Elf_Phdr() {};
   493     Elf_Phdr(std::ifstream &file, char ei_class, char ei_data)
   494     : serializable<Elf_Phdr_Traits>(file, ei_class, ei_data) {};
   495     bool contains(ElfSection *section)
   496     {
   497         unsigned int size = section->getSize();
   498         unsigned int addr = section->getAddr();
   499         // This may be biased, but should work in most cases
   500         if ((section->getFlags() & SHF_ALLOC) == 0)
   501             return false;
   502         // Special case for PT_DYNAMIC. Eventually, this should
   503         // be better handled than special cases
   504         if ((p_type == PT_DYNAMIC) && (section->getType() != SHT_DYNAMIC))
   505             return false;
   506         // Special case for PT_TLS.
   507         if ((p_type == PT_TLS) && !(section->getFlags() & SHF_TLS))
   508             return false;
   509         return (addr >= p_vaddr) &&
   510                (addr + size <= p_vaddr + p_memsz);
   512     }
   513 };
   515 typedef serializable<Elf_Dyn_Traits> Elf_Dyn;
   517 struct Elf_DynValue {
   518     unsigned int tag;
   519     ElfValue *value;
   520 };
   522 class ElfDynamic_Section: public ElfSection {
   523 public:
   524     ElfDynamic_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent);
   525     ~ElfDynamic_Section();
   527     void serialize(std::ofstream &file, char ei_class, char ei_data);
   529     ElfValue *getValueForType(unsigned int tag);
   530     ElfSection *getSectionForType(unsigned int tag);
   531     bool setValueForType(unsigned int tag, ElfValue *val);
   532 private:
   533     std::vector<Elf_DynValue> dyns;
   534 };
   536 typedef serializable<Elf_Sym_Traits> Elf_Sym;
   538 struct Elf_SymValue {
   539     const char *name;
   540     unsigned char info;
   541     unsigned char other;
   542     ElfLocation value;
   543     unsigned int size;
   544     bool defined;
   545 };
   547 #define STT(type) (1 << STT_ ##type)
   549 class ElfSymtab_Section: public ElfSection {
   550 public:
   551     ElfSymtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent);
   553     void serialize(std::ofstream &file, char ei_class, char ei_data);
   555     Elf_SymValue *lookup(const char *name, unsigned int type_filter = STT(OBJECT) | STT(FUNC));
   557 //private: // Until we have a real API
   558     std::vector<Elf_SymValue> syms;
   559 };
   561 class Elf_Rel: public serializable<Elf_Rel_Traits> {
   562 public:
   563     Elf_Rel(std::ifstream &file, char ei_class, char ei_data)
   564     : serializable<Elf_Rel_Traits>(file, ei_class, ei_data) {};
   566     static const unsigned int sh_type = SHT_REL;
   567     static const unsigned int d_tag = DT_REL;
   568     static const unsigned int d_tag_count = DT_RELCOUNT;
   569 };
   571 class Elf_Rela: public serializable<Elf_Rela_Traits> {
   572 public:
   573     Elf_Rela(std::ifstream &file, char ei_class, char ei_data)
   574     : serializable<Elf_Rela_Traits>(file, ei_class, ei_data) {};
   576     static const unsigned int sh_type = SHT_RELA;
   577     static const unsigned int d_tag = DT_RELA;
   578     static const unsigned int d_tag_count = DT_RELACOUNT;
   579 };
   581 template <class Rel>
   582 class ElfRel_Section: public ElfSection {
   583 public:
   584     ElfRel_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
   585     : ElfSection(s, file, parent)
   586     {
   587         int pos = file->tellg();
   588         file->seekg(shdr.sh_offset);
   589         for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) {
   590             Rel r(*file, parent->getClass(), parent->getData());
   591             rels.push_back(r);
   592         }
   593         file->seekg(pos);
   594     }
   596     void serialize(std::ofstream &file, char ei_class, char ei_data)
   597     {
   598         for (typename std::vector<Rel>::iterator i = rels.begin();
   599              i != rels.end(); ++i)
   600             (*i).serialize(file, ei_class, ei_data);
   601     }
   602 //private: // Until we have a real API
   603     std::vector<Rel> rels;
   604 };
   606 class ElfStrtab_Section: public ElfSection {
   607 public:
   608     ElfStrtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
   609     : ElfSection(s, file, parent)
   610     {
   611         table.push_back(table_storage(data, shdr.sh_size));
   612     }
   614     ~ElfStrtab_Section()
   615     {
   616         for (std::vector<table_storage>::iterator t = table.begin() + 1;
   617              t != table.end(); t++)
   618             delete[] t->buf;
   619     }
   621     const char *getStr(unsigned int index);
   623     const char *getStr(const char *string);
   625     unsigned int getStrIndex(const char *string);
   627     void serialize(std::ofstream &file, char ei_class, char ei_data);
   628 private:
   629     struct table_storage {
   630         unsigned int size, used;
   631         char *buf;
   633         table_storage(): size(4096), used(0), buf(new char[4096]) {}
   634         table_storage(const char *data, unsigned int sz)
   635         : size(sz), used(sz), buf(const_cast<char *>(data)) {}
   636     };
   637     std::vector<table_storage> table;
   638 };
   640 inline char Elf::getClass() {
   641     return ehdr->e_ident[EI_CLASS];
   642 }
   644 inline char Elf::getData() {
   645     return ehdr->e_ident[EI_DATA];
   646 }
   648 inline char Elf::getType() {
   649     return ehdr->e_type;
   650 }
   652 inline char Elf::getMachine() {
   653     return ehdr->e_machine;
   654 }
   656 inline unsigned int Elf::getSize() {
   657     ElfSection *section;
   658     for (section = shdr_section /* It's usually not far from the end */;
   659         section->getNext() != nullptr; section = section->getNext());
   660     return section->getOffset() + section->getSize();
   661 }
   663 inline ElfSegment *ElfSection::getSegmentByType(unsigned int type) {
   664     for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
   665         if ((*seg)->getType() == type)
   666             return *seg;
   667     return nullptr;
   668 }
   670 inline void ElfSection::insertInSegments(std::vector<ElfSegment *> &segs) {
   671     for (std::vector<ElfSegment *>::iterator it = segs.begin(); it != segs.end(); ++it) {
   672         (*it)->addSection(this);
   673     }
   674 }
   676 inline ElfLocation::ElfLocation(ElfSection *section, unsigned int off, enum position pos)
   677 : section(section) {
   678     if ((pos == ABSOLUTE) && section)
   679         offset = off - section->getAddr();
   680     else
   681         offset = off;
   682 }
   684 inline ElfLocation::ElfLocation(unsigned int location, Elf *elf) {
   685     section = elf->getSectionAt(location);
   686     offset = location - (section ? section->getAddr() : 0);
   687 }
   689 inline unsigned int ElfLocation::getValue() {
   690     return (section ? section->getAddr() : 0) + offset;
   691 }
   693 inline const char *ElfLocation::getBuffer() {
   694     return section ? section->getData() + offset : nullptr;
   695 }
   697 inline unsigned int ElfSize::getValue() {
   698     return section->getSize();
   699 }
   701 inline unsigned int ElfEntSize::getValue() {
   702     return section->getEntSize();
   703 }

mercurial