Back to index

enigmail  1.4.3
elf.cpp
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 #undef NDEBUG
00039 #include <cstring>
00040 #include <assert.h>
00041 #include "elfxx.h"
00042 
00043 template <class endian, typename R, typename T>
00044 void Elf_Ehdr_Traits::swap(T &t, R &r)
00045 {
00046     memcpy(r.e_ident, t.e_ident, sizeof(r.e_ident));
00047     r.e_type = endian::swap(t.e_type);
00048     r.e_machine = endian::swap(t.e_machine);
00049     r.e_version = endian::swap(t.e_version);
00050     r.e_entry = endian::swap(t.e_entry);
00051     r.e_phoff = endian::swap(t.e_phoff);
00052     r.e_shoff = endian::swap(t.e_shoff);
00053     r.e_flags = endian::swap(t.e_flags);
00054     r.e_ehsize = endian::swap(t.e_ehsize);
00055     r.e_phentsize = endian::swap(t.e_phentsize);
00056     r.e_phnum = endian::swap(t.e_phnum);
00057     r.e_shentsize = endian::swap(t.e_shentsize);
00058     r.e_shnum = endian::swap(t.e_shnum);
00059     r.e_shstrndx = endian::swap(t.e_shstrndx);
00060 }
00061 
00062 template <class endian, typename R, typename T>
00063 void Elf_Phdr_Traits::swap(T &t, R &r)
00064 {
00065     r.p_type = endian::swap(t.p_type);
00066     r.p_offset = endian::swap(t.p_offset);
00067     r.p_vaddr = endian::swap(t.p_vaddr);
00068     r.p_paddr = endian::swap(t.p_paddr);
00069     r.p_filesz = endian::swap(t.p_filesz);
00070     r.p_memsz = endian::swap(t.p_memsz);
00071     r.p_flags = endian::swap(t.p_flags);
00072     r.p_align = endian::swap(t.p_align);
00073 }
00074 
00075 template <class endian, typename R, typename T>
00076 void Elf_Shdr_Traits::swap(T &t, R &r)
00077 {
00078     r.sh_name = endian::swap(t.sh_name);
00079     r.sh_type = endian::swap(t.sh_type);
00080     r.sh_flags = endian::swap(t.sh_flags);
00081     r.sh_addr = endian::swap(t.sh_addr);
00082     r.sh_offset = endian::swap(t.sh_offset);
00083     r.sh_size = endian::swap(t.sh_size);
00084     r.sh_link = endian::swap(t.sh_link);
00085     r.sh_info = endian::swap(t.sh_info);
00086     r.sh_addralign = endian::swap(t.sh_addralign);
00087     r.sh_entsize = endian::swap(t.sh_entsize);
00088 }
00089 
00090 template <class endian, typename R, typename T>
00091 void Elf_Dyn_Traits::swap(T &t, R &r)
00092 {
00093     r.d_tag = endian::swap(t.d_tag);
00094     r.d_un.d_val = endian::swap(t.d_un.d_val);
00095 }
00096 
00097 template <class endian, typename R, typename T>
00098 void Elf_Sym_Traits::swap(T &t, R &r)
00099 {
00100     r.st_name = endian::swap(t.st_name);
00101     r.st_value = endian::swap(t.st_value);
00102     r.st_size = endian::swap(t.st_size);
00103     r.st_info = t.st_info;
00104     r.st_other = t.st_other;
00105     r.st_shndx = endian::swap(t.st_shndx);
00106 }
00107 
00108 template <class endian>
00109 struct _Rel_info {
00110     static inline void swap(Elf32_Word &t, Elf32_Word &r) { r = endian::swap(t); }
00111     static inline void swap(Elf64_Xword &t, Elf64_Xword &r) { r = endian::swap(t); }
00112     static inline void swap(Elf64_Xword &t, Elf32_Word &r) {
00113         r = endian::swap(ELF32_R_INFO(ELF64_R_SYM(t), ELF64_R_TYPE(t)));
00114     }
00115     static inline void swap(Elf32_Word &t, Elf64_Xword &r) {
00116         r = endian::swap(ELF64_R_INFO(ELF32_R_SYM(t), ELF32_R_TYPE(t)));
00117     }
00118 };
00119 
00120 template <class endian, typename R, typename T>
00121 void Elf_Rel_Traits::swap(T &t, R &r)
00122 {
00123     r.r_offset = endian::swap(t.r_offset);
00124     _Rel_info<endian>::swap(t.r_info, r.r_info);
00125 }
00126 
00127 template <class endian, typename R, typename T>
00128 void Elf_Rela_Traits::swap(T &t, R &r)
00129 {
00130     r.r_offset = endian::swap(t.r_offset);
00131     _Rel_info<endian>::swap(t.r_info, r.r_info);
00132     r.r_addend = endian::swap(t.r_addend);
00133 }
00134 
00135 static const Elf32_Shdr null32_section =
00136     { 0, SHT_NULL, 0, 0, 0, 0, SHN_UNDEF, 0, 0, 0 };
00137 
00138 Elf_Shdr null_section(null32_section);
00139 
00140 Elf_Ehdr::Elf_Ehdr(std::ifstream &file, char ei_class, char ei_data)
00141 : serializable<Elf_Ehdr_Traits>(file, ei_class, ei_data),
00142   ElfSection(null_section, NULL, NULL)
00143 {
00144     shdr.sh_size = Elf_Ehdr::size(ei_class);
00145 }
00146 
00147 Elf::Elf(std::ifstream &file)
00148 {
00149     if (!file.is_open())
00150         throw std::runtime_error("Error opening file");
00151 
00152     file.exceptions(std::ifstream::eofbit | std::ifstream::failbit | std::ifstream::badbit);
00153     // Read ELF magic number and identification information
00154     char e_ident[EI_VERSION];
00155     file.seekg(0);
00156     file.read(e_ident, sizeof(e_ident));
00157     file.seekg(0);
00158     ehdr = new Elf_Ehdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
00159 
00160     // ELFOSABI_LINUX is kept unsupported because I haven't looked whether
00161     // STB_GNU_UNIQUE or STT_GNU_IFUNC would need special casing.
00162     if ((ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE) && (ehdr->e_ident[EI_ABIVERSION] != 0))
00163         throw std::runtime_error("unsupported ELF ABI");
00164 
00165     if (ehdr->e_version != 1)
00166         throw std::runtime_error("unsupported ELF version");
00167 
00168     // Sanity checks
00169     if (ehdr->e_shnum == 0)
00170         throw std::runtime_error("sstripped ELF files aren't supported");
00171 
00172     if (ehdr->e_ehsize != Elf_Ehdr::size(e_ident[EI_CLASS]))
00173         throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_ehsize != sizeof(ehdr)");
00174 
00175     if (ehdr->e_shentsize != Elf_Shdr::size(e_ident[EI_CLASS]))
00176         throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_shentsize != sizeof(shdr)");
00177 
00178     if (ehdr->e_phnum == 0) {
00179         if (ehdr->e_phoff != 0)
00180             throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phoff != 0");
00181         if (ehdr->e_phentsize != 0)
00182             throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phentsize != 0");
00183     } else if (ehdr->e_phoff != ehdr->e_ehsize)
00184         throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phoff != ehdr->e_ehsize");
00185     else if (ehdr->e_phentsize != Elf_Phdr::size(e_ident[EI_CLASS]))
00186         throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phentsize != sizeof(phdr)");
00187 
00188     // Read section headers
00189     Elf_Shdr **shdr = new Elf_Shdr *[ehdr->e_shnum];
00190     file.seekg(ehdr->e_shoff);
00191     for (int i = 0; i < ehdr->e_shnum; i++)
00192         shdr[i] = new Elf_Shdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
00193 
00194     // Sanity check in section header for index 0
00195     if ((shdr[0]->sh_name != 0) || (shdr[0]->sh_type != SHT_NULL) ||
00196         (shdr[0]->sh_flags != 0) || (shdr[0]->sh_addr != 0) ||
00197         (shdr[0]->sh_offset != 0) || (shdr[0]->sh_size != 0) ||
00198         (shdr[0]->sh_link != SHN_UNDEF) || (shdr[0]->sh_info != 0) ||
00199         (shdr[0]->sh_addralign != 0) || (shdr[0]->sh_entsize != 0))
00200         throw std::runtime_error("Section header for index 0 contains unsupported values");
00201 
00202     if ((shdr[ehdr->e_shstrndx]->sh_link != 0) || (shdr[ehdr->e_shstrndx]->sh_info != 0))
00203         throw std::runtime_error("unsupported ELF content: string table with sh_link != 0 || sh_info != 0");
00204 
00205     // Store these temporarily
00206     tmp_shdr = shdr;
00207     tmp_file = &file;
00208 
00209     // Fill sections list
00210     sections = new ElfSection *[ehdr->e_shnum];
00211     for (int i = 0; i < ehdr->e_shnum; i++)
00212         sections[i] = NULL;
00213     for (int i = 1; i < ehdr->e_shnum; i++) {
00214         if (sections[i] != NULL)
00215             continue;
00216         getSection(i);
00217     }
00218     Elf_Shdr s;
00219     s.sh_name = 0;
00220     s.sh_type = SHT_NULL;
00221     s.sh_flags = 0;
00222     s.sh_addr = 0;
00223     s.sh_offset = ehdr->e_shoff;
00224     s.sh_entsize = Elf_Shdr::size(e_ident[EI_CLASS]);
00225     s.sh_size = s.sh_entsize * ehdr->e_shnum;
00226     s.sh_link = 0;
00227     s.sh_info = 0;
00228     s.sh_addralign = (e_ident[EI_CLASS] == ELFCLASS32) ? 4 : 8;
00229     shdr_section = new ElfSection(s, NULL, NULL);
00230 
00231     // Fake section for program headers
00232     s.sh_offset = ehdr->e_phoff;
00233     s.sh_addr = ehdr->e_phoff;
00234     s.sh_entsize = Elf_Phdr::size(e_ident[EI_CLASS]);
00235     s.sh_size = s.sh_entsize * ehdr->e_phnum;
00236     phdr_section = new ElfSection(s, NULL, NULL);
00237 
00238     phdr_section->insertAfter(ehdr, false);
00239 
00240     sections[1]->insertAfter(phdr_section, false);
00241     for (int i = 2; i < ehdr->e_shnum; i++) {
00242         // TODO: this should be done in a better way
00243         if ((shdr_section->getPrevious() == NULL) && (shdr[i]->sh_offset > ehdr->e_shoff)) {
00244             shdr_section->insertAfter(sections[i - 1], false);
00245             sections[i]->insertAfter(shdr_section, false);
00246         } else
00247             sections[i]->insertAfter(sections[i - 1], false);
00248     }
00249     if (shdr_section->getPrevious() == NULL)
00250         shdr_section->insertAfter(sections[ehdr->e_shnum - 1], false);
00251 
00252     tmp_file = NULL;
00253     tmp_shdr = NULL;
00254     for (int i = 0; i < ehdr->e_shnum; i++)
00255         delete shdr[i];
00256     delete[] shdr;
00257 
00258     eh_shstrndx = (ElfStrtab_Section *)sections[ehdr->e_shstrndx];
00259 
00260     // Skip reading program headers if there aren't any
00261     if (ehdr->e_phnum == 0)
00262         return;
00263 
00264     // Read program headers
00265     file.seekg(ehdr->e_phoff);
00266     for (int i = 0; i < ehdr->e_phnum; i++) {
00267         Elf_Phdr phdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
00268         if (phdr.p_type == PT_LOAD) {
00269             // Default alignment for PT_LOAD on x86-64 prevents elfhack from
00270             // doing anything useful. However, the system doesn't actually
00271             // require such a big alignment, so in order for elfhack to work
00272             // efficiently, reduce alignment when it's originally the default
00273             // one.
00274             if ((ehdr->e_machine == EM_X86_64) && (phdr.p_align == 0x200000))
00275               phdr.p_align = 0x1000;
00276         }
00277         ElfSegment *segment = new ElfSegment(&phdr);
00278         // Some segments aren't entirely filled (if at all) by sections
00279         // For those, we use fake sections
00280         if ((phdr.p_type == PT_LOAD) && (phdr.p_offset == 0)) {
00281             // Use a fake section for ehdr and phdr
00282             ehdr->getShdr().sh_addr = phdr.p_vaddr;
00283             phdr_section->getShdr().sh_addr += phdr.p_vaddr;
00284             segment->addSection(ehdr);
00285             segment->addSection(phdr_section);
00286         }
00287         if (phdr.p_type == PT_PHDR)
00288             segment->addSection(phdr_section);
00289         for (int j = 1; j < ehdr->e_shnum; j++)
00290             if (phdr.contains(sections[j]))
00291                 segment->addSection(sections[j]);
00292         // Make sure that our view of segments corresponds to the original
00293         // ELF file.
00294         assert(segment->getFileSize() == phdr.p_filesz);
00295         assert(segment->getMemSize() == phdr.p_memsz);
00296         segments.push_back(segment);
00297     }
00298 
00299     new (&eh_entry) ElfLocation(ehdr->e_entry, this);
00300 }
00301 
00302 Elf::~Elf()
00303 {
00304     for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
00305         delete *seg;
00306     delete[] sections;
00307     ElfSection *section = ehdr;
00308     while (section != NULL) {
00309         ElfSection *next = section->getNext();
00310         delete section;
00311         section = next;
00312     }
00313 }
00314 
00315 // TODO: This shouldn't fail after inserting sections
00316 ElfSection *Elf::getSection(int index)
00317 {
00318     if ((index < -1) || (index >= ehdr->e_shnum))
00319         throw std::runtime_error("Section index out of bounds");
00320     if (index == -1)
00321         index = ehdr->e_shstrndx; // TODO: should be fixed to use the actual current number
00322     // Special case: the section at index 0 is void
00323     if (index == 0)
00324         return NULL;
00325     // Infinite recursion guard
00326     if (sections[index] == (ElfSection *)this)
00327         return NULL;
00328     if (sections[index] == NULL) {
00329         sections[index] = (ElfSection *)this;
00330         switch (tmp_shdr[index]->sh_type) {
00331         case SHT_DYNAMIC:
00332             sections[index] = new ElfDynamic_Section(*tmp_shdr[index], tmp_file, this);
00333             break;
00334         case SHT_REL:
00335             sections[index] = new ElfRel_Section<Elf_Rel>(*tmp_shdr[index], tmp_file, this);
00336             break;
00337         case SHT_RELA:
00338             sections[index] = new ElfRel_Section<Elf_Rela>(*tmp_shdr[index], tmp_file, this);
00339             break;
00340         case SHT_DYNSYM:
00341         case SHT_SYMTAB:
00342             sections[index] = new ElfSymtab_Section(*tmp_shdr[index], tmp_file, this);
00343             break;
00344         case SHT_STRTAB:
00345             sections[index] = new ElfStrtab_Section(*tmp_shdr[index], tmp_file, this);
00346             break;
00347         default:
00348             sections[index] = new ElfSection(*tmp_shdr[index], tmp_file, this);
00349         }
00350     }
00351     return sections[index];
00352 }
00353 
00354 ElfSection *Elf::getSectionAt(unsigned int offset)
00355 {
00356     for (int i = 1; i < ehdr->e_shnum; i++) {
00357         ElfSection *section = getSection(i);
00358         if ((section != NULL) && (section->getFlags() & SHF_ALLOC) && !(section->getFlags() & SHF_TLS) &&
00359             (offset >= section->getAddr()) && (offset < section->getAddr() + section->getSize()))
00360             return section;
00361     }
00362     return NULL;
00363 }
00364 
00365 ElfSegment *Elf::getSegmentByType(unsigned int type)
00366 {
00367     for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
00368         if ((*seg)->getType() == type)
00369             return *seg;
00370     return NULL;
00371 }
00372 
00373 ElfDynamic_Section *Elf::getDynSection()
00374 {
00375     for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
00376         if (((*seg)->getType() == PT_DYNAMIC) && ((*seg)->getFirstSection() != NULL) &&
00377             (*seg)->getFirstSection()->getType() == SHT_DYNAMIC)
00378             return (ElfDynamic_Section *)(*seg)->getFirstSection();
00379 
00380     return NULL;
00381 }
00382 
00383 void Elf::write(std::ofstream &file)
00384 {
00385     // fixup section headers sh_name; TODO: that should be done by sections
00386     // themselves
00387     for (ElfSection *section = ehdr; section != NULL; section = section->getNext()) {
00388         if (section->getIndex() == 0)
00389             continue;
00390         else
00391             ehdr->e_shnum = section->getIndex() + 1;
00392         section->getShdr().sh_name = eh_shstrndx->getStrIndex(section->getName());
00393     }
00394     ehdr->markDirty();
00395     // Adjust PT_LOAD segments
00396     int i = 0;
00397     for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++, i++) {
00398         if ((*seg)->getType() == PT_LOAD) {
00399             std::list<ElfSection *>::iterator it = (*seg)->begin();
00400             for (ElfSection *last = *(it++); it != (*seg)->end(); last = *(it++)) {
00401                if (((*it)->getType() != SHT_NOBITS) &&
00402                    ((*it)->getAddr() - last->getAddr()) != ((*it)->getOffset() - last->getOffset())) {
00403                    std::vector<ElfSegment *>::iterator next = seg;
00404                    segments.insert(++next, (*seg)->splitBefore(*it));
00405                    seg = segments.begin() + i;
00406                    break;
00407                }
00408            }
00409         }
00410     }
00411     // fixup ehdr before writing
00412     if (ehdr->e_phnum != segments.size()) {
00413         ehdr->e_phnum = segments.size();
00414         phdr_section->getShdr().sh_size = segments.size() * Elf_Phdr::size(ehdr->e_ident[EI_CLASS]);
00415         phdr_section->getNext()->markDirty();
00416     }
00417     // fixup shdr before writing
00418     if (ehdr->e_shnum != shdr_section->getSize() / shdr_section->getEntSize())
00419         shdr_section->getShdr().sh_size = ehdr->e_shnum * Elf_Shdr::size(ehdr->e_ident[EI_CLASS]);
00420     ehdr->e_shoff = shdr_section->getOffset();
00421     ehdr->e_entry = eh_entry.getValue();
00422     ehdr->e_shstrndx = eh_shstrndx->getIndex();
00423     for (ElfSection *section = ehdr;
00424          section != NULL; section = section->getNext()) {
00425         file.seekp(section->getOffset());
00426         if (section == phdr_section) {
00427             for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++) {
00428                 Elf_Phdr phdr;
00429                 phdr.p_type = (*seg)->getType();
00430                 phdr.p_flags = (*seg)->getFlags();
00431                 phdr.p_offset = (*seg)->getOffset();
00432                 phdr.p_vaddr = (*seg)->getAddr();
00433                 phdr.p_paddr = phdr.p_vaddr + (*seg)->getVPDiff();
00434                 phdr.p_filesz = (*seg)->getFileSize();
00435                 phdr.p_memsz = (*seg)->getMemSize();
00436                 phdr.p_align = (*seg)->getAlign();
00437                 phdr.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
00438             }
00439         } else if (section == shdr_section) {
00440             null_section.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
00441             for (ElfSection *sec = ehdr; sec!= NULL; sec = sec->getNext()) {
00442                 if (sec->getType() != SHT_NULL)
00443                     sec->getShdr().serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
00444             }
00445         } else
00446            section->serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
00447     }
00448 }
00449 
00450 ElfSection::ElfSection(Elf_Shdr &s, std::ifstream *file, Elf *parent)
00451 : shdr(s),
00452   link(shdr.sh_link == SHN_UNDEF ? NULL : parent->getSection(shdr.sh_link)),
00453   next(NULL), previous(NULL), index(-1)
00454 {
00455     if ((file == NULL) || (shdr.sh_type == SHT_NULL) || (shdr.sh_type == SHT_NOBITS))
00456         data = NULL;
00457     else {
00458         data = new char[shdr.sh_size];
00459         int pos = file->tellg();
00460         file->seekg(shdr.sh_offset);
00461         file->read(data, shdr.sh_size);
00462         file->seekg(pos);
00463     }
00464     if (shdr.sh_name == 0)
00465         name = NULL;
00466     else {
00467         ElfStrtab_Section *strtab = (ElfStrtab_Section *) parent->getSection(-1);
00468         // Special case (see elfgeneric.cpp): if strtab is NULL, the
00469         // section being created is the strtab.
00470         if (strtab == NULL)
00471             name = &data[shdr.sh_name];
00472         else
00473             name = strtab->getStr(shdr.sh_name);
00474     }
00475     // Only SHT_REL/SHT_RELA sections use sh_info to store a section
00476     // number.
00477     if ((shdr.sh_type == SHT_REL) || (shdr.sh_type == SHT_RELA))
00478         info.section = shdr.sh_info ? parent->getSection(shdr.sh_info) : NULL;
00479     else
00480         info.index = shdr.sh_info;
00481 }
00482 
00483 unsigned int ElfSection::getAddr()
00484 {
00485     if (shdr.sh_addr != (Elf32_Word)-1)
00486         return shdr.sh_addr;
00487 
00488     // It should be safe to adjust sh_addr for all allocated sections that
00489     // are neither SHT_NOBITS nor SHT_PROGBITS
00490     if ((previous != NULL) && isRelocatable()) {
00491         unsigned int addr = previous->getAddr();
00492         if (previous->getType() != SHT_NOBITS)
00493             addr += previous->getSize();
00494 
00495         if (addr & (getAddrAlign() - 1))
00496             addr = (addr | (getAddrAlign() - 1)) + 1;
00497 
00498         return (shdr.sh_addr = addr);
00499     }
00500     return shdr.sh_addr;
00501 }
00502 
00503 unsigned int ElfSection::getOffset()
00504 {
00505     if (shdr.sh_offset != (Elf32_Word)-1)
00506         return shdr.sh_offset;
00507 
00508     if (previous == NULL)
00509         return (shdr.sh_offset = 0);
00510 
00511     unsigned int offset = previous->getOffset();
00512     if (previous->getType() != SHT_NOBITS)
00513         offset += previous->getSize();
00514 
00515     Elf32_Word align = 0x1000;
00516     for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
00517         align = std::max(align, (*seg)->getAlign());
00518 
00519     Elf32_Word mask = align - 1;
00520     // SHF_TLS is used for .tbss which is some kind of special case.
00521     if (((getType() != SHT_NOBITS) || (getFlags() & SHF_TLS)) && (getFlags() & SHF_ALLOC)) {
00522         if ((getAddr() & mask) < (offset & mask))
00523             offset = (offset | mask) + (getAddr() & mask) + 1;
00524         else
00525             offset = (offset & ~mask) + (getAddr() & mask);
00526     }
00527     if ((getType() != SHT_NOBITS) && (offset & (getAddrAlign() - 1)))
00528         offset = (offset | (getAddrAlign() - 1)) + 1;
00529 
00530     // Two subsequent sections can't be mapped in the same page in memory
00531     // if they aren't in the same 4K block on disk.
00532     if ((getType() != SHT_NOBITS) && getAddr()) {
00533         if (((offset >> 12) != (previous->getOffset() >> 12)) &&
00534             ((getAddr() >> 12) == (previous->getAddr() >> 12)))
00535             throw std::runtime_error("Moving section would require overlapping segments");
00536     }
00537 
00538     return (shdr.sh_offset = offset);
00539 }
00540 
00541 int ElfSection::getIndex()
00542 {
00543     if (index != -1)
00544         return index;
00545     if (getType() == SHT_NULL)
00546         return (index = 0);
00547     ElfSection *reference;
00548     for (reference = previous; (reference != NULL) && (reference->getType() == SHT_NULL); reference = reference->getPrevious());
00549     if (reference == NULL)
00550         return (index = 1);
00551     return (index = reference->getIndex() + 1);
00552 }
00553 
00554 Elf_Shdr &ElfSection::getShdr()
00555 {
00556     getOffset();
00557     if (shdr.sh_link == (Elf32_Word)-1)
00558         shdr.sh_link = getLink() ? getLink()->getIndex() : 0;
00559     if (shdr.sh_info == (Elf32_Word)-1)
00560         shdr.sh_info = ((getType() == SHT_REL) || (getType() == SHT_RELA)) ?
00561                        (getInfo().section ? getInfo().section->getIndex() : 0) :
00562                        getInfo().index;
00563 
00564     return shdr;
00565 }
00566 
00567 ElfSegment::ElfSegment(Elf_Phdr *phdr)
00568 : type(phdr->p_type), v_p_diff(phdr->p_paddr - phdr->p_vaddr),
00569   flags(phdr->p_flags), align(phdr->p_align), vaddr(phdr->p_vaddr),
00570   filesz(phdr->p_filesz), memsz(phdr->p_memsz) {}
00571 
00572 void ElfSegment::addSection(ElfSection *section)
00573 {
00574     // Make sure all sections in PT_GNU_RELRO won't be moved by elfhack
00575     assert(!((type == PT_GNU_RELRO) && (section->isRelocatable())));
00576 
00577     //TODO: Check overlapping sections
00578     std::list<ElfSection *>::iterator i;
00579     for (i = sections.begin(); i != sections.end(); ++i)
00580         if ((*i)->getAddr() > section->getAddr())
00581             break;
00582     sections.insert(i, section);
00583     section->addToSegment(this);
00584 }
00585 
00586 unsigned int ElfSegment::getFileSize()
00587 {
00588     if (type == PT_GNU_RELRO)
00589         return filesz;
00590 
00591     if (sections.empty())
00592         return 0;
00593     // Search the last section that is not SHT_NOBITS
00594     std::list<ElfSection *>::reverse_iterator i;
00595     for (i = sections.rbegin(); (i != sections.rend()) && ((*i)->getType() == SHT_NOBITS); ++i);
00596     // All sections are SHT_NOBITS
00597     if (i == sections.rend())
00598         return 0;
00599 
00600     unsigned int end = (*i)->getAddr() + (*i)->getSize();
00601 
00602     return end - sections.front()->getAddr();
00603 }
00604 
00605 unsigned int ElfSegment::getMemSize()
00606 {
00607     if (type == PT_GNU_RELRO)
00608         return memsz;
00609 
00610     if (sections.empty())
00611         return 0;
00612 
00613     unsigned int end = sections.back()->getAddr() + sections.back()->getSize();
00614 
00615     return end - sections.front()->getAddr();
00616 }
00617 
00618 unsigned int ElfSegment::getOffset()
00619 {
00620     if ((type == PT_GNU_RELRO) && !sections.empty() &&
00621         (sections.front()->getAddr() != vaddr))
00622         throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
00623 
00624     return sections.empty() ? 0 : sections.front()->getOffset();
00625 }
00626 
00627 unsigned int ElfSegment::getAddr()
00628 {
00629     if ((type == PT_GNU_RELRO) && !sections.empty() &&
00630         (sections.front()->getAddr() != vaddr))
00631         throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
00632 
00633     return sections.empty() ? 0 : sections.front()->getAddr();
00634 }
00635 
00636 ElfSegment *ElfSegment::splitBefore(ElfSection *section)
00637 {
00638     std::list<ElfSection *>::iterator i, rm;
00639     for (i = sections.begin(); (*i != section) && (i != sections.end()); ++i);
00640     if (i == sections.end())
00641         return NULL;
00642 
00643     // Probably very wrong.
00644     Elf_Phdr phdr;
00645     phdr.p_type = type;
00646     phdr.p_vaddr = 0;
00647     phdr.p_paddr = phdr.p_vaddr + v_p_diff;
00648     phdr.p_flags = flags;
00649     phdr.p_align = getAlign();
00650     phdr.p_filesz = (unsigned int)-1;
00651     phdr.p_memsz = (unsigned int)-1;
00652     ElfSegment *segment = new ElfSegment(&phdr);
00653 
00654     for (rm = i; i != sections.end(); ++i) {
00655         (*i)->removeFromSegment(this);
00656         segment->addSection(*i);
00657     }
00658     sections.erase(rm, sections.end());
00659 
00660     return segment;
00661 }
00662 
00663 ElfValue *ElfDynamic_Section::getValueForType(unsigned int tag)
00664 {
00665     for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++)
00666         if (dyns[i].tag == tag)
00667             return dyns[i].value;
00668 
00669     return NULL;
00670 }
00671 
00672 ElfSection *ElfDynamic_Section::getSectionForType(unsigned int tag)
00673 {
00674     ElfValue *value = getValueForType(tag);
00675     return value ? value->getSection() : NULL;
00676 }
00677 
00678 void ElfDynamic_Section::setValueForType(unsigned int tag, ElfValue *val)
00679 {
00680     unsigned int i;
00681     for (i = 0; (i < shdr.sh_size / shdr.sh_entsize) && (dyns[i].tag != DT_NULL); i++)
00682         if (dyns[i].tag == tag) {
00683             delete dyns[i].value;
00684             dyns[i].value = val;
00685             return;
00686         }
00687     // This should never happen, as the last entry is always tagged DT_NULL
00688     assert(i < shdr.sh_size / shdr.sh_entsize);
00689     // If we get here, this means we didn't match for the given tag
00690     dyns[i].tag = tag;
00691     dyns[i++].value = val;
00692 
00693     // If we were on the last entry, we need to grow the section.
00694     // Most of the time, though, there are a few DT_NULL entries.
00695     if (i < shdr.sh_size / shdr.sh_entsize)
00696         return;
00697 
00698     Elf_DynValue value;
00699     value.tag = DT_NULL;
00700     value.value = NULL;
00701     dyns.push_back(value);
00702     // Resize the section accordingly
00703     shdr.sh_size += shdr.sh_entsize;
00704     if (getNext() != NULL)
00705         getNext()->markDirty();
00706 }
00707 
00708 ElfDynamic_Section::ElfDynamic_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
00709 : ElfSection(s, file, parent)
00710 {
00711     int pos = file->tellg();
00712     dyns.resize(s.sh_size / s.sh_entsize);
00713     file->seekg(shdr.sh_offset);
00714     // Here we assume tags refer to only one section (e.g. DT_RELSZ accounts
00715     // for .rel.dyn size)
00716     for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) {
00717         Elf_Dyn dyn(*file, parent->getClass(), parent->getData());
00718         dyns[i].tag = dyn.d_tag;
00719         switch (dyn.d_tag) {
00720         case DT_NULL:
00721         case DT_SYMBOLIC:
00722         case DT_TEXTREL:
00723         case DT_BIND_NOW:
00724             dyns[i].value = new ElfValue();
00725             break;
00726         case DT_NEEDED:
00727         case DT_SONAME:
00728         case DT_RPATH:
00729         case DT_PLTREL:
00730         case DT_RUNPATH:
00731         case DT_FLAGS:
00732         case DT_RELACOUNT:
00733         case DT_RELCOUNT:
00734         case DT_VERDEFNUM:
00735         case DT_VERNEEDNUM:
00736             dyns[i].value = new ElfPlainValue(dyn.d_un.d_val);
00737             break;
00738         case DT_PLTGOT:
00739         case DT_HASH:
00740         case DT_STRTAB:
00741         case DT_SYMTAB:
00742         case DT_RELA:
00743         case DT_INIT:
00744         case DT_FINI:
00745         case DT_REL:
00746         case DT_JMPREL:
00747         case DT_INIT_ARRAY:
00748         case DT_FINI_ARRAY:
00749         case DT_GNU_HASH:
00750         case DT_VERSYM:
00751         case DT_VERNEED:
00752         case DT_VERDEF:
00753             dyns[i].value = new ElfLocation(dyn.d_un.d_ptr, parent);
00754             break;
00755         default:
00756             dyns[i].value = NULL;
00757         }
00758     }
00759     // Another loop to get the section sizes
00760     for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++)
00761         switch (dyns[i].tag) {
00762         case DT_PLTRELSZ:
00763             dyns[i].value = new ElfSize(getSectionForType(DT_JMPREL));
00764             break;
00765         case DT_RELASZ:
00766             dyns[i].value = new ElfSize(getSectionForType(DT_RELA));
00767             break;
00768         case DT_STRSZ:
00769             dyns[i].value = new ElfSize(getSectionForType(DT_STRTAB));
00770             break;
00771         case DT_RELSZ:
00772             dyns[i].value = new ElfSize(getSectionForType(DT_REL));
00773             break;
00774         case DT_INIT_ARRAYSZ:
00775             dyns[i].value = new ElfSize(getSectionForType(DT_INIT_ARRAY));
00776             break;
00777         case DT_FINI_ARRAYSZ:
00778             dyns[i].value = new ElfSize(getSectionForType(DT_FINI_ARRAY));
00779             break;
00780         case DT_RELAENT:
00781             dyns[i].value = new ElfEntSize(getSectionForType(DT_RELA));
00782             break;
00783         case DT_SYMENT:
00784             dyns[i].value = new ElfEntSize(getSectionForType(DT_SYMTAB));
00785             break;
00786         case DT_RELENT:
00787             dyns[i].value = new ElfEntSize(getSectionForType(DT_REL));
00788             break;
00789         }
00790 
00791     file->seekg(pos);
00792 }
00793 
00794 ElfDynamic_Section::~ElfDynamic_Section()
00795 {
00796     for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++)
00797         delete dyns[i].value;
00798 }
00799 
00800 void ElfDynamic_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
00801 {
00802     for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
00803         Elf_Dyn dyn;
00804         dyn.d_tag = dyns[i].tag;
00805         dyn.d_un.d_val = (dyns[i].value != NULL) ? dyns[i].value->getValue() : 0;
00806         dyn.serialize(file, ei_class, ei_data);
00807     }
00808 }
00809 
00810 ElfSymtab_Section::ElfSymtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
00811 : ElfSection(s, file, parent)
00812 {
00813     int pos = file->tellg();
00814     syms.resize(s.sh_size / s.sh_entsize);
00815     ElfStrtab_Section *strtab = (ElfStrtab_Section *)getLink();
00816     file->seekg(shdr.sh_offset);
00817     for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
00818         Elf_Sym sym(*file, parent->getClass(), parent->getData());
00819         syms[i].name = strtab->getStr(sym.st_name);
00820         syms[i].info = sym.st_info;
00821         syms[i].other = sym.st_other;
00822         ElfSection *section = (sym.st_shndx == SHN_ABS) ? NULL : parent->getSection(sym.st_shndx);
00823         new (&syms[i].value) ElfLocation(section, sym.st_value, ElfLocation::ABSOLUTE);
00824         syms[i].size = sym.st_size;
00825         syms[i].defined = (sym.st_shndx != SHN_UNDEF);
00826     }
00827     file->seekg(pos);
00828 }
00829 
00830 void
00831 ElfSymtab_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
00832 {
00833     ElfStrtab_Section *strtab = (ElfStrtab_Section *)getLink();
00834     for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
00835         Elf_Sym sym;
00836         sym.st_name = strtab->getStrIndex(syms[i].name);
00837         sym.st_info = syms[i].info;
00838         sym.st_other = syms[i].other;
00839         sym.st_value = syms[i].value.getValue();
00840         ElfSection *section = syms[i].value.getSection();
00841         if (syms[i].defined)
00842             sym.st_shndx = section ? section->getIndex() : SHN_ABS;
00843         else
00844             sym.st_shndx = SHN_UNDEF;
00845         sym.st_size = syms[i].size;
00846         sym.serialize(file, ei_class, ei_data);
00847     }
00848 }
00849 
00850 Elf_SymValue *
00851 ElfSymtab_Section::lookup(const char *name, unsigned int type_filter)
00852 {
00853     for (std::vector<Elf_SymValue>::iterator sym = syms.begin();
00854          sym != syms.end(); sym++) {
00855         if ((type_filter & (1 << ELF32_ST_TYPE(sym->info))) &&
00856             (strcmp(sym->name, name) == 0)) {
00857             return &*sym;
00858         }
00859     }
00860     return NULL;
00861 }
00862 
00863 const char *
00864 ElfStrtab_Section::getStr(unsigned int index)
00865 {
00866     for (std::vector<table_storage>::iterator t = table.begin();
00867          t != table.end(); t++) {
00868         if (index < t->used)
00869             return t->buf + index;
00870         index -= t->used;
00871     }
00872     assert(1 == 0);
00873     return NULL;
00874 }
00875 
00876 const char *
00877 ElfStrtab_Section::getStr(const char *string)
00878 {
00879     if (string == NULL)
00880         return NULL;
00881 
00882     // If the given string is within the section, return it
00883     for (std::vector<table_storage>::iterator t = table.begin();
00884          t != table.end(); t++)
00885         if ((string >= t->buf) && (string < t->buf + t->used))
00886             return string;
00887 
00888     // TODO: should scan in the section to find an existing string
00889 
00890     // If not, we need to allocate the string in the section
00891     size_t len = strlen(string) + 1;
00892 
00893     if (table.back().size - table.back().used < len)
00894         table.resize(table.size() + 1);
00895 
00896     char *alloc_str = table.back().buf + table.back().used;
00897     memcpy(alloc_str, string, len);
00898     table.back().used += len;
00899 
00900     shdr.sh_size += len;
00901     markDirty();
00902 
00903     return alloc_str;
00904 }
00905 
00906 unsigned int
00907 ElfStrtab_Section::getStrIndex(const char *string)
00908 {
00909     if (string == NULL)
00910         return 0;
00911 
00912     unsigned int index = 0;
00913     string = getStr(string);
00914     for (std::vector<table_storage>::iterator t = table.begin();
00915          t != table.end(); t++) {
00916         if ((string >= t->buf) && (string < t->buf + t->used))
00917             return index + (string - t->buf);
00918         index += t->used;
00919     }
00920 
00921     assert(1 == 0);
00922     return 0;
00923 }
00924 
00925 void
00926 ElfStrtab_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
00927 {
00928     file.seekp(getOffset());
00929     for (std::vector<table_storage>::iterator t = table.begin();
00930          t != table.end(); t++)
00931         file.write(t->buf, t->used);
00932 }