Back to index

enigmail  1.4.3
elfhack.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 <assert.h>
00040 #include <cstring>
00041 #include <cstdlib>
00042 #include <cstdio>
00043 #include "elfxx.h"
00044 
00045 #define ver "0"
00046 #define elfhack_data ".elfhack.data.v" ver
00047 #define elfhack_text ".elfhack.text.v" ver
00048 
00049 #ifndef R_ARM_V4BX
00050 #define R_ARM_V4BX 0x28
00051 #endif
00052 #ifndef R_ARM_THM_JUMP24
00053 #define R_ARM_THM_JUMP24 0x1e
00054 #endif
00055 
00056 char *rundir = NULL;
00057 
00058 template <typename T>
00059 struct wrapped {
00060     T value;
00061 };
00062 
00063 class Elf_Addr_Traits {
00064 public:
00065     typedef wrapped<Elf32_Addr> Type32;
00066     typedef wrapped<Elf64_Addr> Type64;
00067 
00068     template <class endian, typename R, typename T>
00069     static inline void swap(T &t, R &r) {
00070         r.value = endian::swap(t.value);
00071     }
00072 };
00073 
00074 class Elf_RelHack_Traits {
00075 public:
00076     typedef Elf32_Rel Type32;
00077     typedef Elf32_Rel Type64;
00078 
00079     template <class endian, typename R, typename T>
00080     static inline void swap(T &t, R &r) {
00081         r.r_offset = endian::swap(t.r_offset);
00082         r.r_info = endian::swap(t.r_info);
00083     }
00084 };
00085 
00086 typedef serializable<Elf_RelHack_Traits> Elf_RelHack;
00087 
00088 class ElfRelHack_Section: public ElfSection {
00089 public:
00090     ElfRelHack_Section(Elf_Shdr &s)
00091     : ElfSection(s, NULL, NULL)
00092     {
00093         name = elfhack_data;
00094     };
00095 
00096     void serialize(std::ofstream &file, char ei_class, char ei_data)
00097     {
00098         for (std::vector<Elf_RelHack>::iterator i = rels.begin();
00099              i != rels.end(); ++i)
00100             (*i).serialize(file, ei_class, ei_data);
00101     }
00102 
00103     bool isRelocatable() {
00104         return true;
00105     }
00106 
00107     void push_back(Elf_RelHack &r) {
00108         rels.push_back(r);
00109         shdr.sh_size = rels.size() * shdr.sh_entsize;
00110     }
00111 private:
00112     std::vector<Elf_RelHack> rels;
00113 };
00114 
00115 class ElfRelHackCode_Section: public ElfSection {
00116 public:
00117     ElfRelHackCode_Section(Elf_Shdr &s, Elf &e)
00118     : ElfSection(s, NULL, NULL), parent(e) {
00119         std::string file(rundir);
00120         init = parent.getDynSection()->getSectionForType(DT_INIT);
00121         file += "/inject/";
00122         switch (parent.getMachine()) {
00123         case EM_386:
00124             file += "x86";
00125             break;
00126         case EM_X86_64:
00127             file += "x86_64";
00128             break;
00129         case EM_ARM:
00130             file += "arm";
00131             break;
00132         default:
00133             throw std::runtime_error("unsupported architecture");
00134         }
00135         if (init == NULL)
00136             file += "-noinit";
00137         file += ".o";
00138         std::ifstream inject(file.c_str(), std::ios::in|std::ios::binary);
00139         elf = new Elf(inject);
00140         if (elf->getType() != ET_REL)
00141             throw std::runtime_error("object for injected code is not ET_REL");
00142         if (elf->getMachine() != parent.getMachine())
00143             throw std::runtime_error("architecture of object for injected code doesn't match");
00144 
00145         ElfSymtab_Section *symtab = NULL;
00146 
00147         // Get all executable sections from the injected code object.
00148         // Most of the time, there will only be one for the init function,
00149         // but on e.g. x86, there is a separate section for
00150         // __i686.get_pc_thunk.$reg
00151         // Find the symbol table at the same time.
00152         for (ElfSection *section = elf->getSection(1); section != NULL;
00153              section = section->getNext()) {
00154             if ((section->getType() == SHT_PROGBITS) &&
00155                 (section->getFlags() & SHF_EXECINSTR)) {
00156                 code.push_back(section);
00157                 // We need to align this section depending on the greater
00158                 // alignment required by code sections.
00159                 if (shdr.sh_addralign < section->getAddrAlign())
00160                     shdr.sh_addralign = section->getAddrAlign();
00161             } else if (section->getType() == SHT_SYMTAB) {
00162                 symtab = (ElfSymtab_Section *) section;
00163             }
00164         }
00165         assert(code.size() != 0);
00166         if (symtab == NULL)
00167             throw std::runtime_error("Couldn't find a symbol table for the injected code");
00168 
00169         // Find the init symbol
00170         entry_point = -1;
00171         int shndx = 0;
00172         Elf_SymValue *sym = symtab->lookup("init");
00173         if (sym) {
00174             entry_point = sym->value.getValue();
00175             shndx = sym->value.getSection()->getIndex();
00176         } else
00177             throw std::runtime_error("Couldn't find an 'init' symbol in the injected code");
00178 
00179         // Adjust code sections offsets according to their size
00180         std::vector<ElfSection *>::iterator c = code.begin();
00181         (*c)->getShdr().sh_addr = 0;
00182         for(ElfSection *last = *(c++); c != code.end(); c++) {
00183             unsigned int addr = last->getShdr().sh_addr + last->getSize();
00184             if (addr & ((*c)->getAddrAlign() - 1))
00185                 addr = (addr | ((*c)->getAddrAlign() - 1)) + 1;
00186             (*c)->getShdr().sh_addr = addr;
00187         }
00188         shdr.sh_size = code.back()->getAddr() + code.back()->getSize();
00189         data = new char[shdr.sh_size];
00190         char *buf = data;
00191         for (c = code.begin(); c != code.end(); c++) {
00192             memcpy(buf, (*c)->getData(), (*c)->getSize());
00193             buf += (*c)->getSize();
00194             if ((*c)->getIndex() < shndx)
00195                 entry_point += (*c)->getSize();
00196         }
00197         name = elfhack_text;
00198     }
00199 
00200     ~ElfRelHackCode_Section() {
00201         delete elf;
00202     }
00203 
00204     void serialize(std::ofstream &file, char ei_class, char ei_data)
00205     {
00206         // Readjust code offsets
00207         for (std::vector<ElfSection *>::iterator c = code.begin(); c != code.end(); c++)
00208             (*c)->getShdr().sh_addr += getAddr();
00209 
00210         // Apply relocations
00211         for (ElfSection *rel = elf->getSection(1); rel != NULL; rel = rel->getNext())
00212             if ((rel->getType() == SHT_REL) || (rel->getType() == SHT_RELA)) {
00213                 ElfSection *section = rel->getInfo().section;
00214                 if ((section->getType() == SHT_PROGBITS) && (section->getFlags() & SHF_EXECINSTR)) {
00215                     if (rel->getType() == SHT_REL)
00216                         apply_relocations((ElfRel_Section<Elf_Rel> *)rel, section);
00217                     else
00218                         apply_relocations((ElfRel_Section<Elf_Rela> *)rel, section);
00219                 }
00220             }
00221 
00222         ElfSection::serialize(file, ei_class, ei_data);
00223     }
00224 
00225     bool isRelocatable() {
00226         return true;
00227     }
00228 
00229     unsigned int getEntryPoint() {
00230         return entry_point;
00231     }
00232 private:
00233     class pc32_relocation {
00234     public:
00235         Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
00236                               Elf32_Word addend, unsigned int addr)
00237         {
00238             return addr + addend - offset - base_addr;
00239         }
00240     };
00241 
00242     class arm_plt32_relocation {
00243     public:
00244         Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
00245                               Elf32_Word addend, unsigned int addr)
00246         {
00247             // We don't care about sign_extend because the only case where this is
00248             // going to be used only jumps forward.
00249             Elf32_Addr tmp = (Elf32_Addr) (addr - offset - base_addr) >> 2;
00250             tmp = (addend + tmp) & 0x00ffffff;
00251             return (addend & 0xff000000) | tmp;
00252         }
00253     };
00254 
00255     class arm_thm_jump24_relocation {
00256     public:
00257         Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
00258                               Elf32_Word addend, unsigned int addr)
00259         {
00260             /* Follows description of b.w instructions as per
00261                ARM Architecture Reference Manual ARMĀ® v7-A and ARMĀ® v7-R edition, A8.6.16
00262                We limit ourselves to Encoding T3.
00263                We don't care about sign_extend because the only case where this is
00264                going to be used only jumps forward. */
00265             Elf32_Addr tmp = (Elf32_Addr) (addr - offset - base_addr);
00266             unsigned int word0 = addend & 0xffff,
00267                          word1 = addend >> 16;
00268 
00269             if (((word0 & 0xf800) != 0xf000) || ((word1 & 0xd000) != 0x9000))
00270                 throw std::runtime_error("R_ARM_THM_JUMP24 relocation only supported for B.W <label>");
00271 
00272             unsigned int s = (word0 & (1 << 10)) >> 10;
00273             unsigned int j1 = (word1 & (1 << 13)) >> 13;
00274             unsigned int j2 = (word1 & (1 << 11)) >> 11;
00275             unsigned int i1 = j1 ^ s ? 0 : 1;
00276             unsigned int i2 = j2 ^ s ? 0 : 1;
00277 
00278             tmp += ((s << 24) | (i1 << 23) | (i2 << 22) | ((word0 & 0x3ff) << 12) | ((word1 & 0x7ff) << 1));
00279 
00280             s = (tmp & (1 << 24)) >> 24;
00281             j1 = ((tmp & (1 << 23)) >> 23) ^ !s;
00282             j2 = ((tmp & (1 << 22)) >> 22) ^ !s;
00283 
00284             return 0xf000 | (s << 10) | ((tmp & (0x3ff << 12)) >> 12) | 
00285                    (0x9000 << 16) | (j1 << 29) | (j2 << 27) | ((tmp & 0xffe) << 15);
00286         }
00287     };
00288 
00289     class gotoff_relocation {
00290     public:
00291         Elf32_Addr operator()(unsigned int base_addr, Elf32_Off offset,
00292                               Elf32_Word addend, unsigned int addr)
00293         {
00294             return addr + addend;
00295         }
00296     };
00297 
00298     template <class relocation_type>
00299     void apply_relocation(ElfSection *the_code, char *base, Elf_Rel *r, unsigned int addr)
00300     {
00301         relocation_type relocation;
00302         Elf32_Addr value;
00303         memcpy(&value, base + r->r_offset, 4);
00304         value = relocation(the_code->getAddr(), r->r_offset, value, addr);
00305         memcpy(base + r->r_offset, &value, 4);
00306     }
00307 
00308     template <class relocation_type>
00309     void apply_relocation(ElfSection *the_code, char *base, Elf_Rela *r, unsigned int addr)
00310     {
00311         relocation_type relocation;
00312         Elf32_Addr value = relocation(the_code->getAddr(), r->r_offset, r->r_addend, addr);
00313         memcpy(base + r->r_offset, &value, 4);
00314     }
00315 
00316     template <typename Rel_Type>
00317     void apply_relocations(ElfRel_Section<Rel_Type> *rel, ElfSection *the_code)
00318     {
00319         assert(rel->getType() == Rel_Type::sh_type);
00320         char *buf = data + (the_code->getAddr() - code.front()->getAddr());
00321         // TODO: various checks on the sections
00322         ElfSymtab_Section *symtab = (ElfSymtab_Section *)rel->getLink();
00323         for (typename std::vector<Rel_Type>::iterator r = rel->rels.begin(); r != rel->rels.end(); r++) {
00324             // TODO: various checks on the symbol
00325             const char *name = symtab->syms[ELF32_R_SYM(r->r_info)].name;
00326             unsigned int addr;
00327             if (symtab->syms[ELF32_R_SYM(r->r_info)].value.getSection() == NULL) {
00328                 if (strcmp(name, "relhack") == 0) {
00329                     addr = getNext()->getAddr();
00330                 } else if (strcmp(name, "elf_header") == 0) {
00331                     // TODO: change this ungly hack to something better
00332                     ElfSection *ehdr = parent.getSection(1)->getPrevious()->getPrevious();
00333                     addr = ehdr->getAddr();
00334                 } else if (strcmp(name, "original_init") == 0) {
00335                     addr = init->getAddr();
00336                 } else if (strcmp(name, "_GLOBAL_OFFSET_TABLE_") == 0) {
00337                     // We actually don't need a GOT, but need it as a reference for
00338                     // GOTOFF relocations. We'll just use the start of the ELF file
00339                     addr = 0;
00340                 } else if (strcmp(name, "") == 0) {
00341                     // This is for R_ARM_V4BX, until we find something better
00342                     addr = -1;
00343                 } else {
00344                     throw std::runtime_error("Unsupported symbol in relocation");
00345                 }
00346             } else {
00347                 ElfSection *section = symtab->syms[ELF32_R_SYM(r->r_info)].value.getSection();
00348                 assert((section->getType() == SHT_PROGBITS) && (section->getFlags() & SHF_EXECINSTR));
00349                 addr = symtab->syms[ELF32_R_SYM(r->r_info)].value.getValue();
00350             }
00351             // Do the relocation
00352 #define REL(machine, type) (EM_ ## machine | (R_ ## machine ## _ ## type << 8))
00353             switch (elf->getMachine() | (ELF32_R_TYPE(r->r_info) << 8)) {
00354             case REL(X86_64, PC32):
00355             case REL(386, PC32):
00356             case REL(386, GOTPC):
00357             case REL(ARM, GOTPC):
00358             case REL(ARM, REL32):
00359                 apply_relocation<pc32_relocation>(the_code, buf, &*r, addr);
00360                 break;
00361             case REL(ARM, PLT32):
00362                 apply_relocation<arm_plt32_relocation>(the_code, buf, &*r, addr);
00363                 break;
00364             case REL(ARM, THM_JUMP24):
00365                 apply_relocation<arm_thm_jump24_relocation>(the_code, buf, &*r, addr);
00366                 break;
00367             case REL(386, GOTOFF):
00368             case REL(ARM, GOTOFF):
00369                 apply_relocation<gotoff_relocation>(the_code, buf, &*r, addr);
00370                 break;
00371             case REL(ARM, V4BX):
00372                 // Ignore R_ARM_V4BX relocations
00373                 break;
00374             default:
00375                 throw std::runtime_error("Unsupported relocation type");
00376             }
00377         }
00378     }
00379 
00380     Elf *elf, &parent;
00381     std::vector<ElfSection *> code;
00382     ElfSection *init;
00383     int entry_point;
00384 };
00385 
00386 template <typename Rel_Type>
00387 int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type2)
00388 {
00389     ElfDynamic_Section *dyn = elf->getDynSection();
00390     if (dyn ==NULL) {
00391         fprintf(stderr, "Couldn't find SHT_DYNAMIC section\n");
00392         return -1;
00393     }
00394 
00395     ElfSegment *relro = elf->getSegmentByType(PT_GNU_RELRO);
00396 
00397     ElfRel_Section<Rel_Type> *section = (ElfRel_Section<Rel_Type> *)dyn->getSectionForType(Rel_Type::d_tag);
00398     assert(section->getType() == Rel_Type::sh_type);
00399 
00400     Elf32_Shdr relhack32_section =
00401         { 0, SHT_PROGBITS, SHF_ALLOC, 0, (Elf32_Off)-1, 0, SHN_UNDEF, 0,
00402           Elf_RelHack::size(elf->getClass()), Elf_RelHack::size(elf->getClass()) }; // TODO: sh_addralign should be an alignment, not size
00403     Elf32_Shdr relhackcode32_section =
00404         { 0, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0, (Elf32_Off)-1, 0,
00405           SHN_UNDEF, 0, 1, 0 };
00406     Elf_Shdr relhack_section(relhack32_section);
00407     Elf_Shdr relhackcode_section(relhackcode32_section);
00408     ElfRelHack_Section *relhack = new ElfRelHack_Section(relhack_section);
00409     ElfRelHackCode_Section *relhackcode = new ElfRelHackCode_Section(relhackcode_section, *elf);
00410 
00411     ElfSymtab_Section *symtab = (ElfSymtab_Section *) section->getLink();
00412     Elf_SymValue *sym = symtab->lookup("__cxa_pure_virtual");
00413 
00414     std::vector<Rel_Type> new_rels;
00415     Elf_RelHack relhack_entry;
00416     relhack_entry.r_offset = relhack_entry.r_info = 0;
00417     int entry_sz = (elf->getClass() == ELFCLASS32) ? 4 : 8;
00418     for (typename std::vector<Rel_Type>::iterator i = section->rels.begin();
00419          i != section->rels.end(); i++) {
00420         // We don't need to keep R_*_NONE relocations
00421         if (!ELF32_R_TYPE(i->r_info))
00422             continue;
00423         ElfSection *section = elf->getSectionAt(i->r_offset);
00424         // __cxa_pure_virtual is a function used in vtables to point at pure
00425         // virtual methods. The __cxa_pure_virtual function usually abort()s.
00426         // These functions are however normally never called. In the case
00427         // where they would, jumping to the NULL address instead of calling
00428         // __cxa_pure_virtual is going to work just as well. So we can remove
00429         // relocations for the __cxa_pure_virtual symbol and NULL out the
00430         // content at the offset pointed by the relocation.
00431         if (sym) {
00432             if (sym->defined) {
00433                 // If we are statically linked to libstdc++, the
00434                 // __cxa_pure_virtual symbol is defined in our lib, and we
00435                 // have relative relocations (rel_type) for it.
00436                 if (ELF32_R_TYPE(i->r_info) == rel_type) {
00437                     serializable<Elf_Addr_Traits> addr(&section->getData()[i->r_offset - section->getAddr()], entry_sz, elf->getClass(), elf->getData());
00438                     if (addr.value == sym->value.getValue()) {
00439                         memset((char *)&section->getData()[i->r_offset - section->getAddr()], 0, entry_sz);
00440                         continue;
00441                     }
00442                 }
00443             } else {
00444                 // If we are dynamically linked to libstdc++, the
00445                 // __cxa_pure_virtual symbol is undefined in our lib, and we
00446                 // have absolute relocations (rel_type2) for it.
00447                 if ((ELF32_R_TYPE(i->r_info) == rel_type2) &&
00448                     (sym == &symtab->syms[ELF32_R_SYM(i->r_info)])) {
00449                     memset((char *)&section->getData()[i->r_offset - section->getAddr()], 0, entry_sz);
00450                     continue;
00451                 }
00452             }
00453         }
00454         // Don't pack relocations happening in non writable sections.
00455         // Our injected code is likely not to be allowed to write there.
00456         if (!(section->getFlags() & SHF_WRITE) || (ELF32_R_TYPE(i->r_info) != rel_type) ||
00457             (relro && (i->r_offset >= relro->getAddr()) &&
00458                       (i->r_offset < relro->getAddr() + relro->getMemSize())))
00459             new_rels.push_back(*i);
00460         else {
00461             // TODO: check that i->r_addend == *i->r_offset
00462             if (i->r_offset == relhack_entry.r_offset + relhack_entry.r_info * entry_sz) {
00463                 relhack_entry.r_info++;
00464             } else {
00465                 if (relhack_entry.r_offset)
00466                     relhack->push_back(relhack_entry);
00467                 relhack_entry.r_offset = i->r_offset;
00468                 relhack_entry.r_info = 1;
00469             }
00470         }
00471     }
00472     if (relhack_entry.r_offset)
00473         relhack->push_back(relhack_entry);
00474     // Last entry must be NULL
00475     relhack_entry.r_offset = relhack_entry.r_info = 0;
00476     relhack->push_back(relhack_entry);
00477 
00478     relhackcode->insertAfter(section);
00479     relhack->insertAfter(relhackcode);
00480 
00481     unsigned int old_end = section->getOffset() + section->getSize();
00482     section->rels.assign(new_rels.begin(), new_rels.end());
00483     section->shrink(new_rels.size() * section->getEntSize());
00484     ElfLocation *init = new ElfLocation(relhackcode, relhackcode->getEntryPoint());
00485     dyn->setValueForType(DT_INIT, init);
00486     // TODO: adjust the value according to the remaining number of relative relocations
00487     if (dyn->getValueForType(Rel_Type::d_tag_count))
00488         dyn->setValueForType(Rel_Type::d_tag_count, new ElfPlainValue(0));
00489 
00490     if (relhack->getOffset() + relhack->getSize() >= old_end) {
00491         fprintf(stderr, "No gain. Skipping\n");
00492         return -1;
00493     }
00494     return 0;
00495 }
00496 
00497 static inline int backup_file(const char *name)
00498 {
00499     std::string fname(name);
00500     fname += ".bak";
00501     return rename(name, fname.c_str());
00502 }
00503 
00504 void do_file(const char *name, bool backup = false, bool force = false)
00505 {
00506     std::ifstream file(name, std::ios::in|std::ios::binary);
00507     Elf *elf = new Elf(file);
00508     unsigned int size = elf->getSize();
00509     fprintf(stderr, "%s: ", name);
00510     if (elf->getType() != ET_DYN) {
00511         fprintf(stderr, "Not a shared object. Skipping\n");
00512         delete elf;
00513         return;
00514     }
00515 
00516     for (ElfSection *section = elf->getSection(1); section != NULL;
00517          section = section->getNext()) {
00518         if (section->getName() &&
00519             (strncmp(section->getName(), ".elfhack.", 9) == 0)) {
00520             fprintf(stderr, "Already elfhacked. Skipping\n");
00521             delete elf;
00522             return;
00523         }
00524     }
00525 
00526     int exit = -1;
00527     switch (elf->getMachine()) {
00528     case EM_386:
00529         exit = do_relocation_section<Elf_Rel>(elf, R_386_RELATIVE, R_386_32);
00530         break;
00531     case EM_X86_64:
00532         exit = do_relocation_section<Elf_Rela>(elf, R_X86_64_RELATIVE, R_X86_64_64);
00533         break;
00534     case EM_ARM:
00535         exit = do_relocation_section<Elf_Rel>(elf, R_ARM_RELATIVE, R_ARM_ABS32);
00536         break;
00537     }
00538     if (exit == 0) {
00539         if (!force && (elf->getSize() >= size)) {
00540             fprintf(stderr, "No gain. Skipping\n");
00541         } else if (backup && backup_file(name) != 0) {
00542             fprintf(stderr, "Couln't create backup file\n");
00543         } else {
00544             std::ofstream ofile(name, std::ios::out|std::ios::binary|std::ios::trunc);
00545             elf->write(ofile);
00546             fprintf(stderr, "Reduced by %d bytes\n", size - elf->getSize());
00547         }
00548     }
00549     delete elf;
00550 }
00551 
00552 int main(int argc, char *argv[])
00553 {
00554     int arg;
00555     bool backup = false;
00556     bool force = false;
00557     char *lastSlash = rindex(argv[0], '/');
00558     if (lastSlash != NULL)
00559         rundir = strndup(argv[0], lastSlash - argv[0]);
00560     for (arg = 1; arg < argc; arg++) {
00561         if (strcmp(argv[arg], "-f") == 0)
00562             force = true;
00563         else if (strcmp(argv[arg], "-b") == 0)
00564             backup = true;
00565         else
00566             do_file(argv[arg], backup, force);
00567     }
00568 
00569     free(rundir);
00570     return 0;
00571 }