Back to index

enigmail  1.4.3
elfxx.h
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is elfhack.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Mozilla Foundation.
00018  * Portions created by the Initial Developer are Copyright (C) 2010
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Mike Hommey <mh@glandium.org>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include <stdexcept>
00039 #include <list>
00040 #include <vector>
00041 #include <cstring>
00042 #include <iostream>
00043 #include <fstream>
00044 #include <algorithm>
00045 #include <elf.h>
00046 #include <asm/byteorder.h>
00047 
00048 // Technically, __*_to_cpu and __cpu_to* function are equivalent,
00049 // so swap can use either of both.
00050 #define def_swap(endian, type, bits) \
00051 static inline type ## bits ## _t swap(type ## bits ## _t i) { \
00052     return __ ## endian ## bits ## _to_cpu(i); \
00053 }
00054 
00055 class little_endian {
00056 public:
00057 def_swap(le, uint, 16);
00058 def_swap(le, uint, 32);
00059 def_swap(le, uint, 64);
00060 def_swap(le, int, 16);
00061 def_swap(le, int, 32);
00062 def_swap(le, int, 64);
00063 };
00064 
00065 class big_endian {
00066 public:
00067 def_swap(be, uint, 16);
00068 def_swap(be, uint, 32);
00069 def_swap(be, uint, 64);
00070 def_swap(be, int, 16);
00071 def_swap(be, int, 32);
00072 def_swap(be, int, 64);
00073 };
00074 
00075 // forward declaration
00076 class ElfSection;
00077 class ElfSegment;
00078 // TODO: Rename Elf_* types
00079 class Elf_Ehdr;
00080 class Elf_Phdr;
00081 class Elf;
00082 class ElfDynamic_Section;
00083 class ElfStrtab_Section;
00084 
00085 class Elf_Ehdr_Traits {
00086 public:
00087     typedef Elf32_Ehdr Type32;
00088     typedef Elf64_Ehdr Type64;
00089 
00090     template <class endian, typename R, typename T>
00091     static void swap(T &t, R &r);
00092 };
00093 
00094 class Elf_Phdr_Traits {
00095 public:
00096     typedef Elf32_Phdr Type32;
00097     typedef Elf64_Phdr Type64;
00098 
00099     template <class endian, typename R, typename T>
00100     static void swap(T &t, R &r);
00101 };
00102 
00103 class Elf_Shdr_Traits {
00104 public:
00105     typedef Elf32_Shdr Type32;
00106     typedef Elf64_Shdr Type64;
00107 
00108     template <class endian, typename R, typename T>
00109     static void swap(T &t, R &r);
00110 };
00111 
00112 class Elf_Dyn_Traits {
00113 public:
00114     typedef Elf32_Dyn Type32;
00115     typedef Elf64_Dyn Type64;
00116 
00117     template <class endian, typename R, typename T>
00118     static void swap(T &t, R &r);
00119 };
00120 
00121 class Elf_Sym_Traits {
00122 public:
00123     typedef Elf32_Sym Type32;
00124     typedef Elf64_Sym Type64;
00125 
00126     template <class endian, typename R, typename T>
00127     static void swap(T &t, R &r);
00128 };
00129 
00130 class Elf_Rel_Traits {
00131 public:
00132     typedef Elf32_Rel Type32;
00133     typedef Elf64_Rel Type64;
00134 
00135     template <class endian, typename R, typename T>
00136     static void swap(T &t, R &r);
00137 };
00138 
00139 class Elf_Rela_Traits {
00140 public:
00141     typedef Elf32_Rela Type32;
00142     typedef Elf64_Rela Type64;
00143 
00144     template <class endian, typename R, typename T>
00145     static void swap(T &t, R &r);
00146 };
00147 
00148 class ElfValue {
00149 public:
00150     virtual unsigned int getValue() { return 0; }
00151     virtual ElfSection *getSection() { return NULL; }
00152 };
00153 
00154 class ElfPlainValue: public ElfValue {
00155     unsigned int value;
00156 public:
00157     ElfPlainValue(unsigned int val): value(val) {};
00158     unsigned int getValue() { return value; }
00159 };
00160 
00161 class ElfLocation: public ElfValue {
00162     ElfSection *section;
00163     unsigned int offset;
00164 public:
00165     enum position { ABSOLUTE, RELATIVE };
00166     ElfLocation(): section(NULL), offset(0) {};
00167     ElfLocation(ElfSection *section, unsigned int off, enum position pos = RELATIVE);
00168     ElfLocation(unsigned int location, Elf *elf);
00169     unsigned int getValue();
00170     ElfSection *getSection() { return section; }
00171 };
00172 
00173 class ElfSize: public ElfValue {
00174     ElfSection *section;
00175 public:
00176     ElfSize(ElfSection *s): section(s) {};
00177     unsigned int getValue();
00178     ElfSection *getSection() { return section; }
00179 };
00180 
00181 class ElfEntSize: public ElfValue {
00182     ElfSection *section;
00183 public:
00184     ElfEntSize(ElfSection *s): section(s) {};
00185     unsigned int getValue();
00186     ElfSection *getSection() { return section; }
00187 };
00188 
00189 template <typename T>
00190 class serializable: public T::Type32 {
00191 public:
00192     serializable() {};
00193     serializable(const typename T::Type32 &p): T::Type32(p) {};
00194 
00195 private:
00196     template <typename R>
00197     void init(const char *buf, size_t len, char ei_data)
00198     {
00199         R e;
00200         assert(len <= sizeof(e));
00201         memcpy(&e, buf, sizeof(e));
00202         if (ei_data == ELFDATA2LSB) {
00203             T::template swap<little_endian>(e, *this);
00204             return;
00205         } else if (ei_data == ELFDATA2MSB) {
00206             T::template swap<big_endian>(e, *this);
00207             return;
00208         }
00209         throw std::runtime_error("Unsupported ELF data encoding");
00210     }
00211 
00212 public:
00213     serializable(const char *buf, size_t len, char ei_class, char ei_data)
00214     {
00215         if (ei_class == ELFCLASS32) {
00216             init<typename T::Type32>(buf, len, ei_data);
00217             return;
00218         } else if (ei_class == ELFCLASS64) {
00219             init<typename T::Type64>(buf, len, ei_data);
00220             return;
00221         }
00222         throw std::runtime_error("Unsupported ELF class");
00223     }
00224 
00225     serializable(std::ifstream &file, char ei_class, char ei_data)
00226     {
00227         if (ei_class == ELFCLASS32) {
00228             typename T::Type32 e;
00229             file.read((char *)&e, sizeof(e));
00230             if (ei_data == ELFDATA2LSB) {
00231                 T::template swap<little_endian>(e, *this);
00232                 return;
00233             } else if (ei_data == ELFDATA2MSB) {
00234                 T::template swap<big_endian>(e, *this);
00235                 return;
00236             }
00237         } else if (ei_class == ELFCLASS64) {
00238             typename T::Type64 e;
00239             file.read((char *)&e, sizeof(e));
00240             if (ei_data == ELFDATA2LSB) {
00241                 T::template swap<little_endian>(e, *this);
00242                 return;
00243             } else if (ei_data == ELFDATA2MSB) {
00244                 T::template swap<big_endian>(e, *this);
00245                 return;
00246             }
00247         }
00248         throw std::runtime_error("Unsupported ELF class or data encoding");
00249     }
00250 
00251     void serialize(std::ofstream &file, char ei_class, char ei_data)
00252     {
00253         if (ei_class == ELFCLASS32) {
00254             typename T::Type32 e;
00255             if (ei_data == ELFDATA2LSB) {
00256                 T::template swap<little_endian>(*this, e);
00257                 file.write((char *)&e, sizeof(e));
00258                 return;
00259             } else if (ei_data == ELFDATA2MSB) {
00260                 T::template swap<big_endian>(*this, e);
00261                 file.write((char *)&e, sizeof(e));
00262                 return;
00263             }
00264         } else if (ei_class == ELFCLASS64) {
00265             typename T::Type64 e;
00266             if (ei_data == ELFDATA2LSB) {
00267                 T::template swap<little_endian>(*this, e);
00268                 file.write((char *)&e, sizeof(e));
00269                 return;
00270             } else if (ei_data == ELFDATA2MSB) {
00271                 T::template swap<big_endian>(*this, e);
00272                 file.write((char *)&e, sizeof(e));
00273                 return;
00274             }
00275         }
00276         throw std::runtime_error("Unsupported ELF class or data encoding");
00277     }
00278 
00279     static inline unsigned int size(char ei_class)
00280     {
00281         if (ei_class == ELFCLASS32)
00282             return sizeof(typename T::Type32);
00283         else if (ei_class == ELFCLASS64)
00284             return sizeof(typename T::Type64);
00285         return 0;
00286     }
00287 };
00288 
00289 typedef serializable<Elf_Shdr_Traits> Elf_Shdr;
00290 
00291 class Elf {
00292 public:
00293     Elf(std::ifstream &file);
00294     ~Elf();
00295 
00296     /* index == -1 is treated as index == ehdr.e_shstrndx */
00297     ElfSection *getSection(int index);
00298 
00299     ElfSection *getSectionAt(unsigned int offset);
00300 
00301     ElfSegment *getSegmentByType(unsigned int type);
00302 
00303     ElfDynamic_Section *getDynSection();
00304 
00305     void write(std::ofstream &file);
00306 
00307     char getClass();
00308     char getData();
00309     char getType();
00310     char getMachine();
00311     unsigned int getSize();
00312 private:
00313     Elf_Ehdr *ehdr;
00314     ElfLocation eh_entry;
00315     ElfStrtab_Section *eh_shstrndx;
00316     ElfSection **sections;
00317     std::vector<ElfSegment *> segments;
00318     ElfSection *shdr_section, *phdr_section;
00319     /* Values used only during initialization */
00320     Elf_Shdr **tmp_shdr;
00321     std::ifstream *tmp_file;
00322 };
00323 
00324 class ElfSection {
00325 public:
00326     typedef union {
00327         ElfSection *section;
00328         int index;
00329     } SectionInfo;
00330 
00331     ElfSection(Elf_Shdr &s, std::ifstream *file, Elf *parent);
00332 
00333     virtual ~ElfSection() {
00334         delete[] data;
00335     }
00336 
00337     const char *getName() { return name; }
00338     unsigned int getType() { return shdr.sh_type; }
00339     unsigned int getFlags() { return shdr.sh_flags; }
00340     unsigned int getAddr();
00341     unsigned int getSize() { return shdr.sh_size; }
00342     unsigned int getAddrAlign() { return shdr.sh_addralign; }
00343     unsigned int getEntSize() { return shdr.sh_entsize; }
00344     const char *getData() { return data; }
00345     ElfSection *getLink() { return link; }
00346     SectionInfo getInfo() { return info; }
00347 
00348     void shrink(unsigned int newsize) {
00349         if (newsize < shdr.sh_size) {
00350             shdr.sh_size = newsize;
00351             if (next)
00352                 next->markDirty();
00353         }
00354     }
00355 
00356     unsigned int getOffset();
00357     int getIndex();
00358     Elf_Shdr &getShdr();
00359 
00360     ElfSection *getNext() { return next; }
00361     ElfSection *getPrevious() { return previous; }
00362 
00363     virtual bool isRelocatable() {
00364         return ((getType() == SHT_SYMTAB) ||
00365                 (getType() == SHT_STRTAB) ||
00366                 (getType() == SHT_RELA) ||
00367                 (getType() == SHT_HASH) ||
00368                 (getType() == SHT_NOTE) ||
00369                 (getType() == SHT_REL) ||
00370                 (getType() == SHT_DYNSYM) ||
00371                 (getType() == SHT_GNU_HASH) ||
00372                 (getType() == SHT_GNU_verdef) ||
00373                 (getType() == SHT_GNU_verneed) ||
00374                 (getType() == SHT_GNU_versym) ||
00375                 isInSegmentType(PT_INTERP)) &&
00376                 (getFlags() & SHF_ALLOC);
00377     }
00378 
00379     void insertAfter(ElfSection *section, bool dirty = true) {
00380         if (previous != NULL)
00381             previous->next = next;
00382         if (next != NULL)
00383             next->previous = previous;
00384         previous = section;
00385         if (section != NULL) {
00386             next = section->next;
00387             section->next = this;
00388         } else
00389             next = NULL;
00390         if (next != NULL)
00391             next->previous = this;
00392         if (dirty)
00393             markDirty();
00394     }
00395 
00396     void markDirty() {
00397         if (link != NULL)
00398             shdr.sh_link = -1;
00399         if (info.index)
00400             shdr.sh_info = -1;
00401         shdr.sh_offset = -1;
00402         if (isRelocatable())
00403             shdr.sh_addr = -1;
00404         if (next)
00405             next->markDirty();
00406     }
00407 
00408     virtual void serialize(std::ofstream &file, char ei_class, char ei_data)
00409     {
00410         if (getType() == SHT_NOBITS)
00411             return;
00412         file.seekp(getOffset());
00413         file.write(data, getSize());
00414     }
00415 
00416 private:
00417     friend class ElfSegment;
00418 
00419     void addToSegment(ElfSegment *segment) {
00420         segments.push_back(segment);
00421     }
00422 
00423     void removeFromSegment(ElfSegment *segment) {
00424         std::vector<ElfSegment *>::iterator i = std::find(segments.begin(), segments.end(), segment);
00425         segments.erase(i, i + 1);
00426     }
00427 
00428     bool isInSegmentType(unsigned int type);
00429 protected:
00430     Elf_Shdr shdr;
00431     char *data;
00432     const char *name;
00433 private:
00434     ElfSection *link;
00435     SectionInfo info;
00436     ElfSection *next, *previous;
00437     int index;
00438     std::vector<ElfSegment *> segments;
00439 };
00440 
00441 class ElfSegment {
00442 public:
00443     ElfSegment(Elf_Phdr *phdr);
00444 
00445     unsigned int getType() { return type; }
00446     unsigned int getFlags() { return flags; }
00447     unsigned int getAlign() { return align; }
00448 
00449     ElfSection *getFirstSection() { return sections.empty() ? NULL : sections.front(); }
00450     int getVPDiff() { return v_p_diff; }
00451     unsigned int getFileSize();
00452     unsigned int getMemSize();
00453     unsigned int getOffset();
00454     unsigned int getAddr();
00455 
00456     void addSection(ElfSection *section);
00457 
00458     std::list<ElfSection *>::iterator begin() { return sections.begin(); }
00459     std::list<ElfSection *>::iterator end() { return sections.end(); }
00460 
00461     ElfSegment *splitBefore(ElfSection *section);
00462 private:
00463     unsigned int type;
00464     int v_p_diff; // Difference between physical and virtual address
00465     unsigned int flags;
00466     unsigned int align;
00467     std::list<ElfSection *> sections;
00468     // The following are only really used for PT_GNU_RELRO until something
00469     // better is found.
00470     unsigned int vaddr;
00471     unsigned int filesz, memsz;
00472 };
00473 
00474 class Elf_Ehdr: public serializable<Elf_Ehdr_Traits>, public ElfSection {
00475 public:
00476     Elf_Ehdr(std::ifstream &file, char ei_class, char ei_data);
00477     void serialize(std::ofstream &file, char ei_class, char ei_data)
00478     {
00479         serializable<Elf_Ehdr_Traits>::serialize(file, ei_class, ei_data);
00480     }
00481 };
00482 
00483 class Elf_Phdr: public serializable<Elf_Phdr_Traits> {
00484 public:
00485     Elf_Phdr() {};
00486     Elf_Phdr(std::ifstream &file, char ei_class, char ei_data)
00487     : serializable<Elf_Phdr_Traits>(file, ei_class, ei_data) {};
00488     bool contains(ElfSection *section)
00489     {
00490         unsigned int size = section->getSize();
00491         unsigned int addr = section->getAddr();
00492         // This may be biased, but should work in most cases
00493         if ((section->getFlags() & SHF_ALLOC) == 0)
00494             return false;
00495         // Special case for PT_DYNAMIC. Eventually, this should
00496         // be better handled than special cases
00497         if ((p_type == PT_DYNAMIC) && (section->getType() != SHT_DYNAMIC))
00498             return false;
00499         // Special case for PT_TLS.
00500         if ((p_type == PT_TLS) && !(section->getFlags() & SHF_TLS))
00501             return false;
00502         return (addr >= p_vaddr) &&
00503                (addr + size <= p_vaddr + p_memsz);
00504 
00505     }
00506 };
00507 
00508 typedef serializable<Elf_Dyn_Traits> Elf_Dyn;
00509 
00510 struct Elf_DynValue {
00511     unsigned int tag;
00512     ElfValue *value;
00513 };
00514 
00515 class ElfDynamic_Section: public ElfSection {
00516 public:
00517     ElfDynamic_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent);
00518     ~ElfDynamic_Section();
00519 
00520     void serialize(std::ofstream &file, char ei_class, char ei_data);
00521 
00522     ElfValue *getValueForType(unsigned int tag);
00523     ElfSection *getSectionForType(unsigned int tag);
00524     void setValueForType(unsigned int tag, ElfValue *val);
00525 private:
00526     std::vector<Elf_DynValue> dyns;
00527 };
00528 
00529 typedef serializable<Elf_Sym_Traits> Elf_Sym;
00530 
00531 struct Elf_SymValue {
00532     const char *name;
00533     unsigned char info;
00534     unsigned char other;
00535     ElfLocation value;
00536     unsigned int size;
00537     bool defined;
00538 };
00539 
00540 #define STT(type) (1 << STT_ ##type)
00541 
00542 class ElfSymtab_Section: public ElfSection {
00543 public:
00544     ElfSymtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent);
00545 
00546     void serialize(std::ofstream &file, char ei_class, char ei_data);
00547 
00548     Elf_SymValue *lookup(const char *name, unsigned int type_filter = STT(OBJECT) | STT(FUNC));
00549 
00550 //private: // Until we have a real API
00551     std::vector<Elf_SymValue> syms;
00552 };
00553 
00554 class Elf_Rel: public serializable<Elf_Rel_Traits> {
00555 public:
00556     Elf_Rel(std::ifstream &file, char ei_class, char ei_data)
00557     : serializable<Elf_Rel_Traits>(file, ei_class, ei_data) {};
00558 
00559     static const unsigned int sh_type = SHT_REL;
00560     static const unsigned int d_tag = DT_REL;
00561     static const unsigned int d_tag_count = DT_RELCOUNT;
00562 };
00563 
00564 class Elf_Rela: public serializable<Elf_Rela_Traits> {
00565 public:
00566     Elf_Rela(std::ifstream &file, char ei_class, char ei_data)
00567     : serializable<Elf_Rela_Traits>(file, ei_class, ei_data) {};
00568 
00569     static const unsigned int sh_type = SHT_RELA;
00570     static const unsigned int d_tag = DT_RELA;
00571     static const unsigned int d_tag_count = DT_RELACOUNT;
00572 };
00573 
00574 template <class Rel>
00575 class ElfRel_Section: public ElfSection {
00576 public:
00577     ElfRel_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
00578     : ElfSection(s, file, parent)
00579     {
00580         int pos = file->tellg();
00581         file->seekg(shdr.sh_offset);
00582         for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) {
00583             Rel r(*file, parent->getClass(), parent->getData());
00584             rels.push_back(r);
00585         }
00586         file->seekg(pos);
00587     }
00588 
00589     void serialize(std::ofstream &file, char ei_class, char ei_data)
00590     {
00591         for (typename std::vector<Rel>::iterator i = rels.begin();
00592              i != rels.end(); ++i)
00593             (*i).serialize(file, ei_class, ei_data);
00594     }
00595 //private: // Until we have a real API
00596     std::vector<Rel> rels;
00597 };
00598 
00599 class ElfStrtab_Section: public ElfSection {
00600 public:
00601     ElfStrtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
00602     : ElfSection(s, file, parent)
00603     {
00604         table.push_back(table_storage(data, shdr.sh_size));
00605     }
00606 
00607     ~ElfStrtab_Section()
00608     {
00609         for (std::vector<table_storage>::iterator t = table.begin() + 1;
00610              t != table.end(); t++)
00611             delete[] t->buf;
00612     }
00613 
00614     const char *getStr(unsigned int index);
00615 
00616     const char *getStr(const char *string);
00617 
00618     unsigned int getStrIndex(const char *string);
00619 
00620     void serialize(std::ofstream &file, char ei_class, char ei_data);
00621 private:
00622     struct table_storage {
00623         unsigned int size, used;
00624         char *buf;
00625 
00626         table_storage(): size(4096), used(0), buf(new char[4096]) {}
00627         table_storage(const char *data, unsigned int sz)
00628         : size(sz), used(sz), buf(const_cast<char *>(data)) {}
00629     };
00630     std::vector<table_storage> table;
00631 };
00632 
00633 inline char Elf::getClass() {
00634     return ehdr->e_ident[EI_CLASS];
00635 }
00636 
00637 inline char Elf::getData() {
00638     return ehdr->e_ident[EI_DATA];
00639 }
00640 
00641 inline char Elf::getType() {
00642     return ehdr->e_type;
00643 }
00644 
00645 inline char Elf::getMachine() {
00646     return ehdr->e_machine;
00647 }
00648 
00649 inline unsigned int Elf::getSize() {
00650     ElfSection *section;
00651     for (section = shdr_section /* It's usually not far from the end */;
00652         section->getNext() != NULL; section = section->getNext());
00653     return section->getOffset() + section->getSize();
00654 }
00655 
00656 inline bool ElfSection::isInSegmentType(unsigned int type) {
00657     for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
00658         if ((*seg)->getType() == type)
00659             return true;
00660     return false;
00661 }
00662 
00663 inline ElfLocation::ElfLocation(ElfSection *section, unsigned int off, enum position pos)
00664 : section(section) {
00665     if ((pos == ABSOLUTE) && section)
00666         offset = off - section->getAddr();
00667     else
00668         offset = off;
00669 }
00670 
00671 inline ElfLocation::ElfLocation(unsigned int location, Elf *elf) {
00672     section = elf->getSectionAt(location);
00673     offset = location - (section ? section->getAddr() : 0);
00674 }
00675 
00676 inline unsigned int ElfLocation::getValue() {
00677     return (section ? section->getAddr() : 0) + offset;
00678 }
00679 
00680 inline unsigned int ElfSize::getValue() {
00681     return section->getSize();
00682 }
00683 
00684 inline unsigned int ElfEntSize::getValue() {
00685     return section->getEntSize();
00686 }