LCOV - code coverage report
Current view: directory - build/unix/elfhack - elfhack.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 277 210 75.8 %
Date: 2012-06-02 Functions: 40 24 60.0 %

       1                 : /* ***** BEGIN LICENSE BLOCK *****
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * The contents of this file are subject to the Mozilla Public License Version
       5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       6                 :  * the License. You may obtain a copy of the License at
       7                 :  * http://www.mozilla.org/MPL/
       8                 :  *
       9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      11                 :  * for the specific language governing rights and limitations under the
      12                 :  * License.
      13                 :  *
      14                 :  * The Original Code is elfhack.
      15                 :  *
      16                 :  * The Initial Developer of the Original Code is
      17                 :  * Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Mike Hommey <mh@glandium.org>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #undef NDEBUG
      39                 : #include <assert.h>
      40                 : #include <cstring>
      41                 : #include <cstdlib>
      42                 : #include <cstdio>
      43                 : #include "elfxx.h"
      44                 : 
      45                 : #define ver "0"
      46                 : #define elfhack_data ".elfhack.data.v" ver
      47                 : #define elfhack_text ".elfhack.text.v" ver
      48                 : 
      49                 : #ifndef R_ARM_V4BX
      50                 : #define R_ARM_V4BX 0x28
      51                 : #endif
      52                 : #ifndef R_ARM_THM_JUMP24
      53                 : #define R_ARM_THM_JUMP24 0x1e
      54                 : #endif
      55                 : 
      56                 : char *rundir = NULL;
      57                 : 
      58                 : template <typename T>
      59               0 : struct wrapped {
      60                 :     T value;
      61                 : };
      62                 : 
      63                 : class Elf_Addr_Traits {
      64                 : public:
      65                 :     typedef wrapped<Elf32_Addr> Type32;
      66                 :     typedef wrapped<Elf64_Addr> Type64;
      67                 : 
      68                 :     template <class endian, typename R, typename T>
      69               0 :     static inline void swap(T &t, R &r) {
      70               0 :         r.value = endian::swap(t.value);
      71               0 :     }
      72                 : };
      73                 : 
      74                 : class Elf_RelHack_Traits {
      75                 : public:
      76                 :     typedef Elf32_Rel Type32;
      77                 :     typedef Elf32_Rel Type64;
      78                 : 
      79                 :     template <class endian, typename R, typename T>
      80           36047 :     static inline void swap(T &t, R &r) {
      81           36047 :         r.r_offset = endian::swap(t.r_offset);
      82           36047 :         r.r_info = endian::swap(t.r_info);
      83           36047 :     }
      84                 : };
      85                 : 
      86                 : typedef serializable<Elf_RelHack_Traits> Elf_RelHack;
      87                 : 
      88              42 : class ElfRelHack_Section: public ElfSection {
      89                 : public:
      90              21 :     ElfRelHack_Section(Elf_Shdr &s)
      91              21 :     : ElfSection(s, NULL, NULL)
      92                 :     {
      93              21 :         name = elfhack_data;
      94              21 :     };
      95                 : 
      96               4 :     void serialize(std::ofstream &file, char ei_class, char ei_data)
      97                 :     {
      98           72102 :         for (std::vector<Elf_RelHack>::iterator i = rels.begin();
      99           36051 :              i != rels.end(); ++i)
     100           36047 :             (*i).serialize(file, ei_class, ei_data);
     101               4 :     }
     102                 : 
     103              79 :     bool isRelocatable() {
     104              79 :         return true;
     105                 :     }
     106                 : 
     107           42350 :     void push_back(Elf_RelHack &r) {
     108           42350 :         rels.push_back(r);
     109           42350 :         shdr.sh_size = rels.size() * shdr.sh_entsize;
     110           42350 :     }
     111                 : private:
     112                 :     std::vector<Elf_RelHack> rels;
     113                 : };
     114                 : 
     115                 : class ElfRelHackCode_Section: public ElfSection {
     116                 : public:
     117              21 :     ElfRelHackCode_Section(Elf_Shdr &s, Elf &e)
     118              21 :     : ElfSection(s, NULL, NULL), parent(e) {
     119              42 :         std::string file(rundir);
     120              21 :         init = parent.getDynSection()->getSectionForType(DT_INIT);
     121              21 :         file += "/inject/";
     122              21 :         switch (parent.getMachine()) {
     123                 :         case EM_386:
     124              21 :             file += "x86";
     125              21 :             break;
     126                 :         case EM_X86_64:
     127               0 :             file += "x86_64";
     128               0 :             break;
     129                 :         case EM_ARM:
     130               0 :             file += "arm";
     131               0 :             break;
     132                 :         default:
     133               0 :             throw std::runtime_error("unsupported architecture");
     134                 :         }
     135              21 :         if (init == NULL)
     136               0 :             file += "-noinit";
     137              21 :         file += ".o";
     138              42 :         std::ifstream inject(file.c_str(), std::ios::in|std::ios::binary);
     139              21 :         elf = new Elf(inject);
     140              21 :         if (elf->getType() != ET_REL)
     141               0 :             throw std::runtime_error("object for injected code is not ET_REL");
     142              21 :         if (elf->getMachine() != parent.getMachine())
     143               0 :             throw std::runtime_error("architecture of object for injected code doesn't match");
     144                 : 
     145              21 :         ElfSymtab_Section *symtab = NULL;
     146                 : 
     147                 :         // Get all executable sections from the injected code object.
     148                 :         // Most of the time, there will only be one for the init function,
     149                 :         // but on e.g. x86, there is a separate section for
     150                 :         // __i686.get_pc_thunk.$reg
     151                 :         // Find the symbol table at the same time.
     152             273 :         for (ElfSection *section = elf->getSection(1); section != NULL;
     153             252 :              section = section->getNext()) {
     154             357 :             if ((section->getType() == SHT_PROGBITS) &&
     155             105 :                 (section->getFlags() & SHF_EXECINSTR)) {
     156              42 :                 code.push_back(section);
     157                 :                 // We need to align this section depending on the greater
     158                 :                 // alignment required by code sections.
     159              42 :                 if (shdr.sh_addralign < section->getAddrAlign())
     160              21 :                     shdr.sh_addralign = section->getAddrAlign();
     161             210 :             } else if (section->getType() == SHT_SYMTAB) {
     162              21 :                 symtab = (ElfSymtab_Section *) section;
     163                 :             }
     164                 :         }
     165              21 :         assert(code.size() != 0);
     166              21 :         if (symtab == NULL)
     167               0 :             throw std::runtime_error("Couldn't find a symbol table for the injected code");
     168                 : 
     169                 :         // Find the init symbol
     170              21 :         entry_point = -1;
     171              21 :         int shndx = 0;
     172              21 :         Elf_SymValue *sym = symtab->lookup("init");
     173              21 :         if (sym) {
     174              21 :             entry_point = sym->value.getValue();
     175              21 :             shndx = sym->value.getSection()->getIndex();
     176                 :         } else
     177               0 :             throw std::runtime_error("Couldn't find an 'init' symbol in the injected code");
     178                 : 
     179                 :         // Adjust code sections offsets according to their size
     180              21 :         std::vector<ElfSection *>::iterator c = code.begin();
     181              21 :         (*c)->getShdr().sh_addr = 0;
     182              42 :         for(ElfSection *last = *(c++); c != code.end(); c++) {
     183              21 :             unsigned int addr = last->getShdr().sh_addr + last->getSize();
     184              21 :             if (addr & ((*c)->getAddrAlign() - 1))
     185               0 :                 addr = (addr | ((*c)->getAddrAlign() - 1)) + 1;
     186              21 :             (*c)->getShdr().sh_addr = addr;
     187                 :         }
     188              21 :         shdr.sh_size = code.back()->getAddr() + code.back()->getSize();
     189              21 :         data = new char[shdr.sh_size];
     190              21 :         char *buf = data;
     191              63 :         for (c = code.begin(); c != code.end(); c++) {
     192              42 :             memcpy(buf, (*c)->getData(), (*c)->getSize());
     193              42 :             buf += (*c)->getSize();
     194              42 :             if ((*c)->getIndex() < shndx)
     195               0 :                 entry_point += (*c)->getSize();
     196                 :         }
     197              21 :         name = elfhack_text;
     198              21 :     }
     199                 : 
     200              63 :     ~ElfRelHackCode_Section() {
     201              21 :         delete elf;
     202              42 :     }
     203                 : 
     204               4 :     void serialize(std::ofstream &file, char ei_class, char ei_data)
     205                 :     {
     206                 :         // Readjust code offsets
     207              12 :         for (std::vector<ElfSection *>::iterator c = code.begin(); c != code.end(); c++)
     208               8 :             (*c)->getShdr().sh_addr += getAddr();
     209                 : 
     210                 :         // Apply relocations
     211              52 :         for (ElfSection *rel = elf->getSection(1); rel != NULL; rel = rel->getNext())
     212              48 :             if ((rel->getType() == SHT_REL) || (rel->getType() == SHT_RELA)) {
     213               4 :                 ElfSection *section = rel->getInfo().section;
     214               4 :                 if ((section->getType() == SHT_PROGBITS) && (section->getFlags() & SHF_EXECINSTR)) {
     215               4 :                     if (rel->getType() == SHT_REL)
     216               4 :                         apply_relocations((ElfRel_Section<Elf_Rel> *)rel, section);
     217                 :                     else
     218               0 :                         apply_relocations((ElfRel_Section<Elf_Rela> *)rel, section);
     219                 :                 }
     220                 :             }
     221                 : 
     222               4 :         ElfSection::serialize(file, ei_class, ei_data);
     223               4 :     }
     224                 : 
     225              79 :     bool isRelocatable() {
     226              79 :         return true;
     227                 :     }
     228                 : 
     229              21 :     unsigned int getEntryPoint() {
     230              21 :         return entry_point;
     231                 :     }
     232                 : private:
     233                 :     class pc32_relocation {
     234                 :     public:
     235              12 :         Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
     236                 :                               Elf32_Word addend, unsigned int addr)
     237                 :         {
     238              12 :             return addr + addend - offset - base_addr;
     239                 :         }
     240                 :     };
     241                 : 
     242                 :     class arm_plt32_relocation {
     243                 :     public:
     244               0 :         Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
     245                 :                               Elf32_Word addend, unsigned int addr)
     246                 :         {
     247                 :             // We don't care about sign_extend because the only case where this is
     248                 :             // going to be used only jumps forward.
     249               0 :             Elf32_Addr tmp = (Elf32_Addr) (addr - offset - base_addr) >> 2;
     250               0 :             tmp = (addend + tmp) & 0x00ffffff;
     251               0 :             return (addend & 0xff000000) | tmp;
     252                 :         }
     253                 :     };
     254                 : 
     255                 :     class arm_thm_jump24_relocation {
     256                 :     public:
     257               0 :         Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
     258                 :                               Elf32_Word addend, unsigned int addr)
     259                 :         {
     260                 :             /* Follows description of b.w instructions as per
     261                 :                ARM Architecture Reference Manual ARMĀ® v7-A and ARMĀ® v7-R edition, A8.6.16
     262                 :                We limit ourselves to Encoding T3.
     263                 :                We don't care about sign_extend because the only case where this is
     264                 :                going to be used only jumps forward. */
     265               0 :             Elf32_Addr tmp = (Elf32_Addr) (addr - offset - base_addr);
     266               0 :             unsigned int word0 = addend & 0xffff,
     267               0 :                          word1 = addend >> 16;
     268                 : 
     269               0 :             if (((word0 & 0xf800) != 0xf000) || ((word1 & 0xd000) != 0x9000))
     270               0 :                 throw std::runtime_error("R_ARM_THM_JUMP24 relocation only supported for B.W <label>");
     271                 : 
     272               0 :             unsigned int s = (word0 & (1 << 10)) >> 10;
     273               0 :             unsigned int j1 = (word1 & (1 << 13)) >> 13;
     274               0 :             unsigned int j2 = (word1 & (1 << 11)) >> 11;
     275               0 :             unsigned int i1 = j1 ^ s ? 0 : 1;
     276               0 :             unsigned int i2 = j2 ^ s ? 0 : 1;
     277                 : 
     278               0 :             tmp += ((s << 24) | (i1 << 23) | (i2 << 22) | ((word0 & 0x3ff) << 12) | ((word1 & 0x7ff) << 1));
     279                 : 
     280               0 :             s = (tmp & (1 << 24)) >> 24;
     281               0 :             j1 = ((tmp & (1 << 23)) >> 23) ^ !s;
     282               0 :             j2 = ((tmp & (1 << 22)) >> 22) ^ !s;
     283                 : 
     284                 :             return 0xf000 | (s << 10) | ((tmp & (0x3ff << 12)) >> 12) | 
     285               0 :                    (0x9000 << 16) | (j1 << 29) | (j2 << 27) | ((tmp & 0xffe) << 15);
     286                 :         }
     287                 :     };
     288                 : 
     289                 :     class gotoff_relocation {
     290                 :     public:
     291              12 :         Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
     292                 :                               Elf32_Word addend, unsigned int addr)
     293                 :         {
     294              12 :             return addr + addend;
     295                 :         }
     296                 :     };
     297                 : 
     298                 :     template <class relocation_type>
     299              24 :     void apply_relocation(ElfSection *the_code, char *base, Elf_Rel *r, unsigned int addr)
     300                 :     {
     301                 :         relocation_type relocation;
     302                 :         Elf32_Addr value;
     303              24 :         memcpy(&value, base + r->r_offset, 4);
     304              24 :         value = relocation(the_code->getAddr(), r->r_offset, value, addr);
     305              24 :         memcpy(base + r->r_offset, &value, 4);
     306              24 :     }
     307                 : 
     308                 :     template <class relocation_type>
     309               0 :     void apply_relocation(ElfSection *the_code, char *base, Elf_Rela *r, unsigned int addr)
     310                 :     {
     311                 :         relocation_type relocation;
     312               0 :         Elf32_Addr value = relocation(the_code->getAddr(), r->r_offset, r->r_addend, addr);
     313               0 :         memcpy(base + r->r_offset, &value, 4);
     314               0 :     }
     315                 : 
     316                 :     template <typename Rel_Type>
     317               4 :     void apply_relocations(ElfRel_Section<Rel_Type> *rel, ElfSection *the_code)
     318                 :     {
     319               4 :         assert(rel->getType() == Rel_Type::sh_type);
     320               4 :         char *buf = data + (the_code->getAddr() - code.front()->getAddr());
     321                 :         // TODO: various checks on the sections
     322               4 :         ElfSymtab_Section *symtab = (ElfSymtab_Section *)rel->getLink();
     323              28 :         for (typename std::vector<Rel_Type>::iterator r = rel->rels.begin(); r != rel->rels.end(); r++) {
     324                 :             // TODO: various checks on the symbol
     325              24 :             const char *name = symtab->syms[ELF32_R_SYM(r->r_info)].name;
     326                 :             unsigned int addr;
     327              24 :             if (symtab->syms[ELF32_R_SYM(r->r_info)].value.getSection() == NULL) {
     328              20 :                 if (strcmp(name, "relhack") == 0) {
     329               8 :                     addr = getNext()->getAddr();
     330              12 :                 } else if (strcmp(name, "elf_header") == 0) {
     331                 :                     // TODO: change this ungly hack to something better
     332               4 :                     ElfSection *ehdr = parent.getSection(1)->getPrevious()->getPrevious();
     333               4 :                     addr = ehdr->getAddr();
     334               8 :                 } else if (strcmp(name, "original_init") == 0) {
     335               4 :                     addr = init->getAddr();
     336               4 :                 } else if (strcmp(name, "_GLOBAL_OFFSET_TABLE_") == 0) {
     337                 :                     // We actually don't need a GOT, but need it as a reference for
     338                 :                     // GOTOFF relocations. We'll just use the start of the ELF file
     339               4 :                     addr = 0;
     340               0 :                 } else if (strcmp(name, "") == 0) {
     341                 :                     // This is for R_ARM_V4BX, until we find something better
     342               0 :                     addr = -1;
     343                 :                 } else {
     344               0 :                     throw std::runtime_error("Unsupported symbol in relocation");
     345                 :                 }
     346                 :             } else {
     347               4 :                 ElfSection *section = symtab->syms[ELF32_R_SYM(r->r_info)].value.getSection();
     348               4 :                 assert((section->getType() == SHT_PROGBITS) && (section->getFlags() & SHF_EXECINSTR));
     349               4 :                 addr = symtab->syms[ELF32_R_SYM(r->r_info)].value.getValue();
     350                 :             }
     351                 :             // Do the relocation
     352                 : #define REL(machine, type) (EM_ ## machine | (R_ ## machine ## _ ## type << 8))
     353              24 :             switch (elf->getMachine() | (ELF32_R_TYPE(r->r_info) << 8)) {
     354                 :             case REL(X86_64, PC32):
     355                 :             case REL(386, PC32):
     356                 :             case REL(386, GOTPC):
     357                 :             case REL(ARM, GOTPC):
     358                 :             case REL(ARM, REL32):
     359              12 :                 apply_relocation<pc32_relocation>(the_code, buf, &*r, addr);
     360              12 :                 break;
     361                 :             case REL(ARM, PLT32):
     362               0 :                 apply_relocation<arm_plt32_relocation>(the_code, buf, &*r, addr);
     363               0 :                 break;
     364                 :             case REL(ARM, THM_JUMP24):
     365               0 :                 apply_relocation<arm_thm_jump24_relocation>(the_code, buf, &*r, addr);
     366               0 :                 break;
     367                 :             case REL(386, GOTOFF):
     368                 :             case REL(ARM, GOTOFF):
     369              12 :                 apply_relocation<gotoff_relocation>(the_code, buf, &*r, addr);
     370              12 :                 break;
     371                 :             case REL(ARM, V4BX):
     372                 :                 // Ignore R_ARM_V4BX relocations
     373               0 :                 break;
     374                 :             default:
     375               0 :                 throw std::runtime_error("Unsupported relocation type");
     376                 :             }
     377                 :         }
     378               4 :     }
     379                 : 
     380                 :     Elf *elf, &parent;
     381                 :     std::vector<ElfSection *> code;
     382                 :     ElfSection *init;
     383                 :     int entry_point;
     384                 : };
     385                 : 
     386                 : template <typename Rel_Type>
     387              21 : int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type2)
     388                 : {
     389              21 :     ElfDynamic_Section *dyn = elf->getDynSection();
     390              21 :     if (dyn ==NULL) {
     391               0 :         fprintf(stderr, "Couldn't find SHT_DYNAMIC section\n");
     392               0 :         return -1;
     393                 :     }
     394                 : 
     395              21 :     ElfSegment *relro = elf->getSegmentByType(PT_GNU_RELRO);
     396                 : 
     397              21 :     ElfRel_Section<Rel_Type> *section = (ElfRel_Section<Rel_Type> *)dyn->getSectionForType(Rel_Type::d_tag);
     398              21 :     assert(section->getType() == Rel_Type::sh_type);
     399                 : 
     400                 :     Elf32_Shdr relhack32_section =
     401                 :         { 0, SHT_PROGBITS, SHF_ALLOC, 0, (Elf32_Off)-1, 0, SHN_UNDEF, 0,
     402              21 :           Elf_RelHack::size(elf->getClass()), Elf_RelHack::size(elf->getClass()) }; // TODO: sh_addralign should be an alignment, not size
     403                 :     Elf32_Shdr relhackcode32_section =
     404                 :         { 0, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0, (Elf32_Off)-1, 0,
     405              21 :           SHN_UNDEF, 0, 1, 0 };
     406              21 :     Elf_Shdr relhack_section(relhack32_section);
     407              21 :     Elf_Shdr relhackcode_section(relhackcode32_section);
     408              21 :     ElfRelHack_Section *relhack = new ElfRelHack_Section(relhack_section);
     409              21 :     ElfRelHackCode_Section *relhackcode = new ElfRelHackCode_Section(relhackcode_section, *elf);
     410                 : 
     411              21 :     ElfSymtab_Section *symtab = (ElfSymtab_Section *) section->getLink();
     412              21 :     Elf_SymValue *sym = symtab->lookup("__cxa_pure_virtual");
     413                 : 
     414              42 :     std::vector<Rel_Type> new_rels;
     415              21 :     Elf_RelHack relhack_entry;
     416              21 :     relhack_entry.r_offset = relhack_entry.r_info = 0;
     417              21 :     int entry_sz = (elf->getClass() == ELFCLASS32) ? 4 : 8;
     418          311624 :     for (typename std::vector<Rel_Type>::iterator i = section->rels.begin();
     419                 :          i != section->rels.end(); i++) {
     420                 :         // We don't need to keep R_*_NONE relocations
     421          311603 :         if (!ELF32_R_TYPE(i->r_info))
     422               0 :             continue;
     423          311603 :         ElfSection *section = elf->getSectionAt(i->r_offset);
     424                 :         // __cxa_pure_virtual is a function used in vtables to point at pure
     425                 :         // virtual methods. The __cxa_pure_virtual function usually abort()s.
     426                 :         // These functions are however normally never called. In the case
     427                 :         // where they would, jumping to the NULL address instead of calling
     428                 :         // __cxa_pure_virtual is going to work just as well. So we can remove
     429                 :         // relocations for the __cxa_pure_virtual symbol and NULL out the
     430                 :         // content at the offset pointed by the relocation.
     431          311603 :         if (sym) {
     432          299981 :             if (sym->defined) {
     433                 :                 // If we are statically linked to libstdc++, the
     434                 :                 // __cxa_pure_virtual symbol is defined in our lib, and we
     435                 :                 // have relative relocations (rel_type) for it.
     436               0 :                 if (ELF32_R_TYPE(i->r_info) == rel_type) {
     437               0 :                     serializable<Elf_Addr_Traits> addr(&section->getData()[i->r_offset - section->getAddr()], entry_sz, elf->getClass(), elf->getData());
     438               0 :                     if (addr.value == sym->value.getValue()) {
     439               0 :                         memset((char *)&section->getData()[i->r_offset - section->getAddr()], 0, entry_sz);
     440               0 :                         continue;
     441                 :                     }
     442                 :                 }
     443                 :             } else {
     444                 :                 // If we are dynamically linked to libstdc++, the
     445                 :                 // __cxa_pure_virtual symbol is undefined in our lib, and we
     446                 :                 // have absolute relocations (rel_type2) for it.
     447          299981 :                 if ((ELF32_R_TYPE(i->r_info) == rel_type2) &&
     448                 :                     (sym == &symtab->syms[ELF32_R_SYM(i->r_info)])) {
     449           31375 :                     memset((char *)&section->getData()[i->r_offset - section->getAddr()], 0, entry_sz);
     450           31375 :                     continue;
     451                 :                 }
     452                 :             }
     453                 :         }
     454                 :         // Don't pack relocations happening in non writable sections.
     455                 :         // Our injected code is likely not to be allowed to write there.
     456          280228 :         if (!(section->getFlags() & SHF_WRITE) || (ELF32_R_TYPE(i->r_info) != rel_type) ||
     457                 :             (relro && (i->r_offset >= relro->getAddr()) &&
     458                 :                       (i->r_offset < relro->getAddr() + relro->getMemSize())))
     459            2988 :             new_rels.push_back(*i);
     460                 :         else {
     461                 :             // TODO: check that i->r_addend == *i->r_offset
     462          277240 :             if (i->r_offset == relhack_entry.r_offset + relhack_entry.r_info * entry_sz) {
     463          234911 :                 relhack_entry.r_info++;
     464                 :             } else {
     465           42329 :                 if (relhack_entry.r_offset)
     466           42308 :                     relhack->push_back(relhack_entry);
     467           42329 :                 relhack_entry.r_offset = i->r_offset;
     468           42329 :                 relhack_entry.r_info = 1;
     469                 :             }
     470                 :         }
     471                 :     }
     472              21 :     if (relhack_entry.r_offset)
     473              21 :         relhack->push_back(relhack_entry);
     474                 :     // Last entry must be NULL
     475              21 :     relhack_entry.r_offset = relhack_entry.r_info = 0;
     476              21 :     relhack->push_back(relhack_entry);
     477                 : 
     478              21 :     relhackcode->insertAfter(section);
     479              21 :     relhack->insertAfter(relhackcode);
     480                 : 
     481              21 :     unsigned int old_end = section->getOffset() + section->getSize();
     482              21 :     section->rels.assign(new_rels.begin(), new_rels.end());
     483              21 :     section->shrink(new_rels.size() * section->getEntSize());
     484              21 :     ElfLocation *init = new ElfLocation(relhackcode, relhackcode->getEntryPoint());
     485              21 :     dyn->setValueForType(DT_INIT, init);
     486                 :     // TODO: adjust the value according to the remaining number of relative relocations
     487              21 :     if (dyn->getValueForType(Rel_Type::d_tag_count))
     488              21 :         dyn->setValueForType(Rel_Type::d_tag_count, new ElfPlainValue(0));
     489                 : 
     490              21 :     if (relhack->getOffset() + relhack->getSize() >= old_end) {
     491               3 :         fprintf(stderr, "No gain. Skipping\n");
     492               3 :         return -1;
     493                 :     }
     494              18 :     return 0;
     495                 : }
     496                 : 
     497               1 : static inline int backup_file(const char *name)
     498                 : {
     499               2 :     std::string fname(name);
     500               1 :     fname += ".bak";
     501               1 :     return rename(name, fname.c_str());
     502                 : }
     503                 : 
     504              21 : void do_file(const char *name, bool backup = false, bool force = false)
     505                 : {
     506              42 :     std::ifstream file(name, std::ios::in|std::ios::binary);
     507              21 :     Elf *elf = new Elf(file);
     508              21 :     unsigned int size = elf->getSize();
     509              21 :     fprintf(stderr, "%s: ", name);
     510              21 :     if (elf->getType() != ET_DYN) {
     511               0 :         fprintf(stderr, "Not a shared object. Skipping\n");
     512               0 :         delete elf;
     513                 :         return;
     514                 :     }
     515                 : 
     516             797 :     for (ElfSection *section = elf->getSection(1); section != NULL;
     517                 :          section = section->getNext()) {
     518            1531 :         if (section->getName() &&
     519             755 :             (strncmp(section->getName(), ".elfhack.", 9) == 0)) {
     520               0 :             fprintf(stderr, "Already elfhacked. Skipping\n");
     521               0 :             delete elf;
     522                 :             return;
     523                 :         }
     524                 :     }
     525                 : 
     526              21 :     int exit = -1;
     527              21 :     switch (elf->getMachine()) {
     528                 :     case EM_386:
     529              21 :         exit = do_relocation_section<Elf_Rel>(elf, R_386_RELATIVE, R_386_32);
     530              21 :         break;
     531                 :     case EM_X86_64:
     532               0 :         exit = do_relocation_section<Elf_Rela>(elf, R_X86_64_RELATIVE, R_X86_64_64);
     533               0 :         break;
     534                 :     case EM_ARM:
     535               0 :         exit = do_relocation_section<Elf_Rel>(elf, R_ARM_RELATIVE, R_ARM_ABS32);
     536               0 :         break;
     537                 :     }
     538              21 :     if (exit == 0) {
     539              18 :         if (!force && (elf->getSize() >= size)) {
     540              14 :             fprintf(stderr, "No gain. Skipping\n");
     541               4 :         } else if (backup && backup_file(name) != 0) {
     542               0 :             fprintf(stderr, "Couln't create backup file\n");
     543                 :         } else {
     544               8 :             std::ofstream ofile(name, std::ios::out|std::ios::binary|std::ios::trunc);
     545               4 :             elf->write(ofile);
     546               4 :             fprintf(stderr, "Reduced by %d bytes\n", size - elf->getSize());
     547                 :         }
     548                 :     }
     549              21 :     delete elf;
     550                 : }
     551                 : 
     552               2 : int main(int argc, char *argv[])
     553                 : {
     554                 :     int arg;
     555               2 :     bool backup = false;
     556               2 :     bool force = false;
     557               2 :     char *lastSlash = rindex(argv[0], '/');
     558               2 :     if (lastSlash != NULL)
     559               2 :         rundir = strndup(argv[0], lastSlash - argv[0]);
     560              25 :     for (arg = 1; arg < argc; arg++) {
     561              23 :         if (strcmp(argv[arg], "-f") == 0)
     562               1 :             force = true;
     563              22 :         else if (strcmp(argv[arg], "-b") == 0)
     564               1 :             backup = true;
     565                 :         else
     566              21 :             do_file(argv[arg], backup, force);
     567                 :     }
     568                 : 
     569               2 :     free(rundir);
     570               2 :     return 0;
     571               6 : }

Generated by: LCOV version 1.7