Home | History | Annotate | Download | only in vtable-dumper
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "elf_handling.h"
     18 
     19 #include <cxxabi.h>
     20 
     21 using llvm::ELF::ELFDATA2MSB;
     22 using llvm::ELF::EM_ARM;
     23 using llvm::ELF::EM_MIPS;
     24 using llvm::ELF::R_AARCH64_ABS64;
     25 using llvm::ELF::R_AARCH64_RELATIVE;
     26 using llvm::ELF::R_ARM_ABS32;
     27 using llvm::ELF::R_ARM_RELATIVE;
     28 using llvm::ELF::R_X86_64_64;
     29 using llvm::ELF::R_X86_64_RELATIVE;
     30 using llvm::ELF::R_MIPS_64;
     31 using llvm::ELF::R_MIPS_REL32;
     32 using llvm::ELF::R_MIPS_NONE;
     33 using llvm::ELF::SHT_PROGBITS;
     34 using llvm::ELF::SHT_REL;
     35 using llvm::ELF::SHT_RELA;
     36 using llvm::Expected;
     37 using llvm::StringRef;
     38 using llvm::dyn_cast;
     39 using llvm::object::ELF32BEObjectFile;
     40 using llvm::object::ELF32LEObjectFile;
     41 using llvm::object::ELF64BEObjectFile;
     42 using llvm::object::ELF64LEObjectFile;
     43 using llvm::object::symbol_iterator;
     44 using llvm::support::endian::read;
     45 using llvm::outs;
     46 using llvm::Error;
     47 using llvm::make_unique;
     48 
     49 static std::string demangle(const std::string &MangledName) {
     50      char *Str = __cxxabiv1::__cxa_demangle(
     51              MangledName.c_str(),
     52              nullptr,
     53              0,
     54              nullptr);
     55      if (Str) {
     56          std::string DemangledString(Str);
     57          free(Str);
     58          return DemangledString;
     59      }
     60      return "";
     61 }
     62 
     63 SharedObject::~SharedObject() {}
     64 
     65 template <typename ELFT>
     66 static std::unique_ptr<SharedObject> createELFSharedObject(
     67         const ELFObjectFile<ELFT> *Objfile) {
     68     return make_unique<ELFSharedObject<ELFT>>(Objfile);
     69 }
     70 
     71 static std::unique_ptr<SharedObject>createELFObjFile(const ObjectFile *Obj) {
     72     if (const ELF32LEObjectFile *Objfile = dyn_cast<ELF32LEObjectFile>(Obj))
     73         return createELFSharedObject(Objfile);
     74     if (const ELF32BEObjectFile *Objfile = dyn_cast<ELF32BEObjectFile>(Obj))
     75         return createELFSharedObject(Objfile);
     76     if (const ELF64LEObjectFile *Objfile = dyn_cast<ELF64LEObjectFile>(Obj))
     77         return createELFSharedObject(Objfile);
     78     if (const ELF64BEObjectFile *Objfile = dyn_cast<ELF64BEObjectFile>(Obj))
     79         return createELFSharedObject(Objfile);
     80 
     81     return nullptr;
     82 }
     83 
     84 std::unique_ptr<SharedObject> SharedObject::create(const ObjectFile *Obj) {
     85     std::unique_ptr<SharedObject> res(createELFObjFile(Obj));
     86     if (res && res->getVTables()) {
     87         return res;
     88     }
     89     return nullptr;
     90 }
     91 
     92 template <typename ELFT>
     93 ELFSharedObject<ELFT>::~ELFSharedObject() {}
     94 
     95 template <typename ELFT>
     96 ELFSharedObject<ELFT>::ELFSharedObject(
     97         const ELFObjectFile<ELFT> *Objfile)
     98     : mObj(Objfile) {}
     99 
    100 template <typename ELFT>
    101 bool ELFSharedObject<ELFT>::cacheELFSections() {
    102     for (const SectionRef &ElfSection : mObj->sections()) {
    103         const Elf_Shdr *ElfShdr =
    104                 mObj->getSection(ElfSection.getRawDataRefImpl());
    105         if (!ElfShdr) {
    106             outs() << "Couldn't create elf shdr \n";
    107             return false;
    108         }
    109         switch (ElfShdr->sh_type) {
    110             case SHT_RELA:
    111             case SHT_REL:
    112                 mRelSectionRefs.emplace_back(ElfSection);
    113                 break;
    114             case SHT_PROGBITS:
    115                 mProgBitSectionRefs.emplace_back(ElfSection);
    116                 break;
    117             default :
    118                 // Any other section won't have information pertinent
    119                 // to vtables. Relocation entries will have the virtual
    120                 // functions' relocation information, the PROGBITS sections
    121                 // will have the vtables themselves.
    122                 break;
    123         }
    124     }
    125     return true;
    126 }
    127 
    128 template <typename ELFT>
    129 void ELFSharedObject<ELFT>::printVTables(bool Mangled) const {
    130     for (const VTable &Vtable : mVTables) {
    131         if (Vtable.getVTableSize() == 0)
    132             continue;
    133         outs() << Vtable.getDemangledName()
    134                << "\n"
    135                << Vtable.getMangledName()
    136                << ": "
    137                << Vtable.getVTableSize()
    138                << " entries"
    139                << "\n";
    140         for (const VFunction &Vfunction : Vtable) {
    141             std::string VfunctionName = (Mangled ?
    142                                          Vfunction.getMangledName() :
    143                                          Vfunction.getDemangledName());
    144             outs() << Vfunction.getOffset()
    145                    << "    (int (*)(...)) "
    146                    << VfunctionName
    147                    << "\n";
    148         }
    149         outs() << "\n"
    150                << "\n";
    151     }
    152 }
    153 
    154 template <typename ELFT>
    155 bool ELFSharedObject<ELFT>::getVTables() {
    156     if (!cacheELFSections()) {
    157         return false;
    158     }
    159     if (!initVTableRanges()) {
    160         return true;
    161     }
    162     getVFunctions();
    163     for (VTable &Vtable : mVTables) {
    164         // Sort the functions by offset before displaying them since the order
    165         // of functions appearing in relocation sections might change. That
    166         // should not result in the vtable layout changing.
    167         Vtable.sortVFunctions();
    168     }
    169     return true;
    170 }
    171 
    172 template <typename ELFT>
    173 bool ELFSharedObject<ELFT>::initVTableRanges() {
    174     // Go through all the symbols in the dynsym / symtab sections
    175     // and cache all the relevant symbols. i.e: symbols which correspond
    176     // to either vtables or functions.
    177 
    178     std::vector<std::pair<SymbolRef, uint64_t>> SymsAndSizes =
    179             computeSymbolSizes(*mObj);
    180     for (std::pair<SymbolRef, uint64_t> &Pair : SymsAndSizes) {
    181         SymbolRef Symbol = Pair.first;
    182         SymbolRef::Type SymType = UnWrap(Symbol.getType());
    183         uint64_t SymValue = Symbol.getValue();
    184         StringRef SymName = UnWrap(Symbol.getName());
    185         if (SymName.startswith("__ZTV") || SymName.startswith("_ZTV")) {
    186             mVTables.emplace_back(
    187                     SymName.str(),
    188                     demangle(SymName.str()),
    189                     Symbol.getValue(),
    190                     Symbol.getValue() + Pair.second);
    191         } else if (SymType == SymbolRef::ST_Function) {
    192             std::map<uint64_t, std::vector<SymbolRef>>::iterator It =
    193                     mAddrToSymbolRef.find(SymValue);
    194             if (It == mAddrToSymbolRef.end()) {
    195                 mAddrToSymbolRef.insert(std::make_pair(
    196                         SymValue, std::vector<SymbolRef>(1, Symbol)));
    197             } else {
    198                 std::vector<SymbolRef> &SymVec = It->second;
    199                 SymVec.emplace_back(Symbol);
    200             }
    201         }
    202     }
    203     if (mVTables.size() == 0) {
    204         return false;
    205     }
    206     std::sort(mVTables.begin(), mVTables.end());
    207     return true;
    208 }
    209 
    210 template <typename ELFT>
    211 void ELFSharedObject<ELFT>::getVFunctions() {
    212     for (const SectionRef &Section : mRelSectionRefs) {
    213         for (const RelocationRef &Relocation : Section.relocations()) {
    214             VTable *VtPtr = identifyVTable(Relocation.getOffset());
    215             if (VtPtr != nullptr) {
    216                 relocateSym(Relocation, Section, VtPtr);
    217             }
    218         }
    219     }
    220 }
    221 
    222 template <typename ELFT>
    223 VTable *ELFSharedObject<ELFT>::identifyVTable(uint64_t RelOffset) {
    224     typename std::vector<VTable>::iterator It;
    225     It = std::lower_bound(mVTables.begin(), mVTables.end(), RelOffset);
    226     if (It != mVTables.begin() && It->getStartAddr() != RelOffset) {
    227         It--;
    228     }
    229     if (It->getEndAddr() >= RelOffset) {
    230         return &(*It);
    231     }
    232     return nullptr;
    233 }
    234 
    235 template <typename ELFT>
    236 void ELFSharedObject<ELFT>::relocateSym(
    237         const RelocationRef &Relocation,
    238         const SectionRef &Section,
    239         VTable *Vtablep) {
    240     const Elf_Ehdr *ElfHeader = mObj->getELFFile()->getHeader();
    241     if (ElfHeader->e_machine == EM_MIPS) {
    242         // bionic/linker/linker_mips.cpp , we handle only one type of
    243         // relocation. Depending on if the symbol can be inferred from r_info we
    244         // make it an absolute or a relative relocation.
    245         if (!absoluteRelocation(Relocation, Vtablep)) {
    246             relativeRelocation(Relocation, Section, Vtablep);
    247         }
    248     } else {
    249         switch(Relocation.getType()) {
    250             case R_AARCH64_RELATIVE:
    251             case R_X86_64_RELATIVE:
    252             case R_ARM_RELATIVE:
    253             {
    254                 // The return value is ignored since failure to relocate
    255                 // does not mean a fatal error. It might be that the dynsym /
    256                 // symbol-table does not have enough information to get the
    257                 // symbol name. Like-wise for absolute relocations.
    258                 relativeRelocation(Relocation, Section, Vtablep);
    259                 break;
    260             }
    261             case R_AARCH64_ABS64:
    262             case R_X86_64_64:
    263             case R_ARM_ABS32:
    264             {
    265                 absoluteRelocation(Relocation, Vtablep);
    266                 break;
    267             }
    268             default:
    269                 break;
    270         }
    271     }
    272 }
    273 
    274 template <typename ELFT>
    275 bool ELFSharedObject<ELFT>::absoluteRelocation(
    276         const RelocationRef &Relocation,
    277         VTable *Vtablep) {
    278     symbol_iterator Symi = Relocation.getSymbol();
    279     if (Symi == mObj->symbol_end()) {
    280         return false;
    281     }
    282     SymbolRef Symbol = *Symi;
    283     uint64_t RelOffset = Relocation.getOffset();
    284     StringRef SymbolName = UnWrap(Symbol.getName());
    285     std::string DemangledName = demangle(SymbolName.str());
    286     if (!DemangledName.empty()) {
    287         Vtablep->addVFunction(SymbolName.str(), DemangledName, RelOffset);
    288         return true;
    289     }
    290     return false;
    291 }
    292 
    293 template <typename ELFT>
    294 bool ELFSharedObject<ELFT>::relativeRelocation(
    295         const RelocationRef &Relocation,
    296         const SectionRef &Section,
    297         VTable *Vtablep) {
    298     uint64_t Addend = 0;
    299     uint64_t RelOffset = Relocation.getOffset();
    300     if (mObj->getSection(Section.getRawDataRefImpl())->sh_type == SHT_RELA) {
    301         const Elf_Rela *Rela = mObj->getRela(Relocation.getRawDataRefImpl());
    302         Addend = static_cast<uint64_t>(Rela->r_addend);
    303     }
    304 
    305     if (Addend == 0) {
    306         Addend = identifyAddend(Relocation.getOffset());
    307     }
    308 
    309     std::map<uint64_t, std::vector<SymbolRef>>::iterator It =
    310             mAddrToSymbolRef.find(Addend);
    311     if (It == mAddrToSymbolRef.end()) {
    312         return false;
    313     }
    314     SymbolRef Symbol = matchValueToSymbol(It->second, Vtablep);
    315     StringRef SymbolName = UnWrap(Symbol.getName());
    316     std::string DemangledName = demangle(SymbolName.str());
    317     if (!DemangledName.empty()) {
    318         Vtablep->addVFunction(SymbolName.str(), DemangledName, RelOffset);
    319         return true;
    320     }
    321     return false;
    322 }
    323 
    324 template <typename ELFT>
    325 SymbolRef ELFSharedObject<ELFT>::matchValueToSymbol(
    326         std::vector<SymbolRef> &SymVec,
    327         VTable *Vtablep) {
    328     constexpr size_t pos = sizeof("vtable for ") - 1;
    329     const std::string ClassName(Vtablep->getDemangledName().substr(pos));
    330     for (const SymbolRef &Symbol : SymVec) {
    331         StringRef SymbolName = UnWrap(Symbol.getName());
    332         if (demangle(SymbolName.str()).find(ClassName) != std::string::npos) {
    333             return Symbol;
    334         }
    335     }
    336     // Return the 1st Symbol by default.
    337     return SymVec[0];
    338 }
    339 
    340 template <typename ELFT>
    341 uint64_t ELFSharedObject<ELFT>::identifyAddend(uint64_t ROffset) {
    342     for (const SectionRef &Section : mProgBitSectionRefs) {
    343         uint64_t Begin = Section.getAddress();
    344         uint64_t End = Section.getAddress() + Section.getSize();
    345         if (ROffset >= Begin && ROffset <= End) {
    346             return getAddendFromSection(Section, ROffset - Begin);
    347         }
    348     }
    349     return 0;
    350 }
    351 
    352 template <typename ELFT>
    353 uint64_t ELFSharedObject<ELFT>::getAddendFromSection(
    354         const SectionRef &Section,
    355         uint64_t Offset) {
    356     StringRef Contents;
    357     if (Section.getContents(Contents))
    358         return 0;
    359     const unsigned char *Bytes = Contents.bytes_begin() + Offset;
    360     uintX_t Addend = read<uintX_t, ELFT::TargetEndianness>(Bytes);
    361     const Elf_Ehdr *ElfHeader = mObj->getELFFile()->getHeader();
    362     if (ElfHeader->e_machine == EM_ARM ||
    363         ElfHeader->e_machine == EM_MIPS) {
    364         // Remove thumb flag as llvm suggests.
    365         Addend &= ~1;
    366     }
    367     return static_cast<uint64_t>(Addend);
    368 }
    369 
    370 VFunction::VFunction(
    371         const std::string &MangledName,
    372         const std::string &DemangledName,
    373         uint64_t VFunctionOffset)
    374     : mMangledName(MangledName),
    375       mDemangledName(DemangledName),
    376       mOffset(VFunctionOffset) {}
    377 
    378 uint64_t VFunction::getOffset() const {
    379     return mOffset;
    380 }
    381 
    382 const std::string &VFunction::getDemangledName() const {
    383     return mDemangledName;
    384 }
    385 
    386 const std::string &VFunction::getMangledName() const {
    387     return mMangledName;
    388 }
    389 
    390 bool VFunction::operator<(const VFunction &Vfunction) const {
    391     return mOffset < Vfunction.getOffset();
    392 }
    393 
    394 VTable::VTable(
    395         const std::string &MangledName,
    396         const std::string &DemangledName,
    397         uint64_t Begin,
    398         uint64_t End)
    399     : mMangledName(MangledName),
    400       mDemangledName(DemangledName),
    401       mStartAddr(Begin),
    402       mEndAddr(End),
    403       mBaseOffset(Begin) {}
    404 
    405 void VTable::addVFunction(
    406         const std::string &MangledName,
    407         const std::string &DemangledName,
    408         uint64_t RelOffset) {
    409     mFunctions.emplace_back(
    410             MangledName,
    411             DemangledName,
    412             RelOffset - mBaseOffset);
    413 }
    414 
    415 const std::string &VTable::getDemangledName() const {
    416     return mDemangledName;
    417 }
    418 
    419 const std::string &VTable::getMangledName() const {
    420     return mMangledName;
    421 }
    422 
    423 uint64_t VTable::getStartAddr() const {
    424     return mStartAddr;
    425 }
    426 
    427 uint64_t VTable::getEndAddr() const {
    428     return mEndAddr;
    429 }
    430 
    431 uint64_t VTable::getBaseOffset() const {
    432     return mBaseOffset;
    433 }
    434 
    435 uint64_t VTable::getVTableSize() const {
    436     return mFunctions.size();
    437 }
    438 
    439 VTable::func_iterator VTable::begin() const {
    440     return mFunctions.cbegin();
    441 }
    442 
    443 VTable::func_iterator VTable::end() const {
    444     return mFunctions.cend();
    445 }
    446 
    447 bool VTable::operator<(const VTable &Vtable) const {
    448     return mStartAddr < Vtable.getStartAddr();
    449 }
    450 
    451 bool VTable::operator<(const uint64_t ROffset) const {
    452     return mStartAddr < ROffset;
    453 }
    454 
    455 void VTable::sortVFunctions() {
    456     std::sort(mFunctions.begin(), mFunctions.end());
    457 }
    458