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() 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             outs() << Vfunction.getOffset()
    142                    << "    (int (*)(...)) "
    143                    << Vfunction.getDemangledName()
    144                    << "\n";
    145         }
    146         outs() << "\n"
    147                << "\n";
    148     }
    149 }
    150 
    151 template <typename ELFT>
    152 bool ELFSharedObject<ELFT>::getVTables() {
    153     if (!cacheELFSections()) {
    154         return false;
    155     }
    156     if (!initVTableRanges()) {
    157         return true;
    158     }
    159     getVFunctions();
    160     for (VTable &Vtable : mVTables) {
    161         // Sort the functions by offset before displaying them since the order
    162         // of functions appearing in relocation sections might change. That
    163         // should not result in the vtable layout changing.
    164         Vtable.sortVFunctions();
    165     }
    166     return true;
    167 }
    168 
    169 template <typename ELFT>
    170 bool ELFSharedObject<ELFT>::initVTableRanges() {
    171     // Go through all the symbols in the dynsym / symtab sections
    172     // and cache all the relevant symbols. i.e: symbols which correspond
    173     // to either vtables or functions.
    174 
    175     std::vector<std::pair<SymbolRef, uint64_t>> SymsAndSizes =
    176             computeSymbolSizes(*mObj);
    177     for (std::pair<SymbolRef, uint64_t> &Pair : SymsAndSizes) {
    178         SymbolRef Symbol = Pair.first;
    179         SymbolRef::Type SymType = UnWrap(Symbol.getType());
    180         uint64_t SymValue = Symbol.getValue();
    181         StringRef SymName = UnWrap(Symbol.getName());
    182         if (SymName.startswith("__ZTV") || SymName.startswith("_ZTV")) {
    183             mVTables.emplace_back(
    184                     SymName.str(),
    185                     demangle(SymName.str()),
    186                     Symbol.getValue(),
    187                     Symbol.getValue() + Pair.second);
    188         } else if (SymType == SymbolRef::ST_Function) {
    189             std::map<uint64_t, std::vector<SymbolRef>>::iterator It =
    190                     mAddrToSymbolRef.find(SymValue);
    191             if (It == mAddrToSymbolRef.end()) {
    192                 mAddrToSymbolRef.insert(std::make_pair(
    193                         SymValue, std::vector<SymbolRef>(1, Symbol)));
    194             } else {
    195                 std::vector<SymbolRef> &SymVec = It->second;
    196                 SymVec.emplace_back(Symbol);
    197             }
    198         }
    199     }
    200     if (mVTables.size() == 0) {
    201         return false;
    202     }
    203     std::sort(mVTables.begin(), mVTables.end());
    204     return true;
    205 }
    206 
    207 template <typename ELFT>
    208 void ELFSharedObject<ELFT>::getVFunctions() {
    209     for (const SectionRef &Section : mRelSectionRefs) {
    210         for (const RelocationRef &Relocation : Section.relocations()) {
    211             VTable *VtPtr = identifyVTable(Relocation.getOffset());
    212             if (VtPtr != nullptr) {
    213                 relocateSym(Relocation, Section, VtPtr);
    214             }
    215         }
    216     }
    217 }
    218 
    219 template <typename ELFT>
    220 VTable *ELFSharedObject<ELFT>::identifyVTable(uint64_t RelOffset) {
    221     typename std::vector<VTable>::iterator It;
    222     It = std::lower_bound(mVTables.begin(), mVTables.end(), RelOffset);
    223     if (It != mVTables.begin() && It->getStartAddr() != RelOffset) {
    224         It--;
    225     }
    226     if (It->getEndAddr() >= RelOffset) {
    227         return &(*It);
    228     }
    229     return nullptr;
    230 }
    231 
    232 template <typename ELFT>
    233 void ELFSharedObject<ELFT>::relocateSym(
    234         const RelocationRef &Relocation,
    235         const SectionRef &Section,
    236         VTable *Vtablep) {
    237     const Elf_Ehdr *ElfHeader = mObj->getELFFile()->getHeader();
    238     if (ElfHeader->e_machine == EM_MIPS) {
    239         // bionic/linker/linker_mips.cpp , we handle only one type of
    240         // relocation. Depending on if the symbol can be inferred from r_info we
    241         // make it an absolute or a relative relocation.
    242         if (!absoluteRelocation(Relocation, Vtablep)) {
    243             relativeRelocation(Relocation, Section, Vtablep);
    244         }
    245     } else {
    246         switch(Relocation.getType()) {
    247             case R_AARCH64_RELATIVE:
    248             case R_X86_64_RELATIVE:
    249             case R_ARM_RELATIVE:
    250             {
    251                 // The return value is ignored since failure to relocate
    252                 // does not mean a fatal error. It might be that the dynsym /
    253                 // symbol-table does not have enough information to get the
    254                 // symbol name. Like-wise for absolute relocations.
    255                 relativeRelocation(Relocation, Section, Vtablep);
    256                 break;
    257             }
    258             case R_AARCH64_ABS64:
    259             case R_X86_64_64:
    260             case R_ARM_ABS32:
    261             {
    262                 absoluteRelocation(Relocation, Vtablep);
    263                 break;
    264             }
    265             default:
    266                 break;
    267         }
    268     }
    269 }
    270 
    271 template <typename ELFT>
    272 bool ELFSharedObject<ELFT>::absoluteRelocation(
    273         const RelocationRef &Relocation,
    274         VTable *Vtablep) {
    275     symbol_iterator Symi = Relocation.getSymbol();
    276     if (Symi == mObj->symbol_end()) {
    277         return false;
    278     }
    279     SymbolRef Symbol = *Symi;
    280     uint64_t RelOffset = Relocation.getOffset();
    281     StringRef SymbolName = UnWrap(Symbol.getName());
    282     std::string DemangledName = demangle(SymbolName.str());
    283     if (!DemangledName.empty()) {
    284         Vtablep->addVFunction(SymbolName.str(), DemangledName, RelOffset);
    285         return true;
    286     }
    287     return false;
    288 }
    289 
    290 template <typename ELFT>
    291 bool ELFSharedObject<ELFT>::relativeRelocation(
    292         const RelocationRef &Relocation,
    293         const SectionRef &Section,
    294         VTable *Vtablep) {
    295     uint64_t Addend = 0;
    296     uint64_t RelOffset = Relocation.getOffset();
    297     if (mObj->getSection(Section.getRawDataRefImpl())->sh_type == SHT_RELA) {
    298         const Elf_Rela *Rela = mObj->getRela(Relocation.getRawDataRefImpl());
    299         Addend = static_cast<uint64_t>(Rela->r_addend);
    300     }
    301 
    302     if (Addend == 0) {
    303         Addend = identifyAddend(Relocation.getOffset());
    304     }
    305 
    306     std::map<uint64_t, std::vector<SymbolRef>>::iterator It =
    307             mAddrToSymbolRef.find(Addend);
    308     if (It == mAddrToSymbolRef.end()) {
    309         return false;
    310     }
    311     SymbolRef Symbol = matchValueToSymbol(It->second, Vtablep);
    312     StringRef SymbolName = UnWrap(Symbol.getName());
    313     std::string DemangledName = demangle(SymbolName.str());
    314     if (!DemangledName.empty()) {
    315         Vtablep->addVFunction(SymbolName.str(), DemangledName, RelOffset);
    316         return true;
    317     }
    318     return false;
    319 }
    320 
    321 template <typename ELFT>
    322 SymbolRef ELFSharedObject<ELFT>::matchValueToSymbol(
    323         std::vector<SymbolRef> &SymVec,
    324         VTable *Vtablep) {
    325     constexpr size_t pos = sizeof("vtable for ") - 1;
    326     const std::string ClassName(Vtablep->getDemangledName().substr(pos));
    327     for (const SymbolRef &Symbol : SymVec) {
    328         StringRef SymbolName = UnWrap(Symbol.getName());
    329         if (SymbolName.str().find(ClassName) != std::string::npos)
    330             return Symbol;
    331     }
    332     // Return the 1st Symbol by default.
    333     return SymVec[0];
    334 }
    335 
    336 template <typename ELFT>
    337 uint64_t ELFSharedObject<ELFT>::identifyAddend(uint64_t ROffset) {
    338     for (const SectionRef &Section : mProgBitSectionRefs) {
    339         uint64_t Begin = Section.getAddress();
    340         uint64_t End = Section.getAddress() + Section.getSize();
    341         if (ROffset >= Begin && ROffset <= End) {
    342             return getAddendFromSection(Section, ROffset - Begin);
    343         }
    344     }
    345     return 0;
    346 }
    347 
    348 template <typename ELFT>
    349 uint64_t ELFSharedObject<ELFT>::getAddendFromSection(
    350         const SectionRef &Section,
    351         uint64_t Offset) {
    352     StringRef Contents;
    353     if (Section.getContents(Contents))
    354         return 0;
    355     const unsigned char *Bytes = Contents.bytes_begin() + Offset;
    356     uintX_t Addend = read<uintX_t, ELFT::TargetEndianness>(Bytes);
    357     const Elf_Ehdr *ElfHeader = mObj->getELFFile()->getHeader();
    358     if (ElfHeader->e_machine == EM_ARM ||
    359         ElfHeader->e_machine == EM_MIPS) {
    360         // Remove thumb flag as llvm suggests.
    361         Addend &= ~1;
    362     }
    363     return static_cast<uint64_t>(Addend);
    364 }
    365 
    366 VFunction::VFunction(
    367         const std::string &MangledName,
    368         const std::string &DemangledName,
    369         uint64_t VFunctionOffset)
    370     : mMangledName(MangledName),
    371       mDemangledName(DemangledName),
    372       mOffset(VFunctionOffset) {}
    373 
    374 uint64_t VFunction::getOffset() const {
    375     return mOffset;
    376 }
    377 
    378 const std::string &VFunction::getDemangledName() const {
    379     return mDemangledName;
    380 }
    381 
    382 const std::string &VFunction::getMangledName() const {
    383     return mMangledName;
    384 }
    385 
    386 bool VFunction::operator<(const VFunction &Vfunction) const {
    387     return mOffset < Vfunction.getOffset();
    388 }
    389 
    390 VTable::VTable(
    391         const std::string &MangledName,
    392         const std::string &DemangledName,
    393         uint64_t Begin,
    394         uint64_t End)
    395     : mMangledName(MangledName),
    396       mDemangledName(DemangledName),
    397       mStartAddr(Begin),
    398       mEndAddr(End),
    399       mBaseOffset(Begin) {}
    400 
    401 void VTable::addVFunction(
    402         const std::string &MangledName,
    403         const std::string &DemangledName,
    404         uint64_t RelOffset) {
    405     mFunctions.emplace_back(
    406             MangledName,
    407             DemangledName,
    408             RelOffset - mBaseOffset);
    409 }
    410 
    411 const std::string &VTable::getDemangledName() const {
    412     return mDemangledName;
    413 }
    414 
    415 const std::string &VTable::getMangledName() const {
    416     return mMangledName;
    417 }
    418 
    419 uint64_t VTable::getStartAddr() const {
    420     return mStartAddr;
    421 }
    422 
    423 uint64_t VTable::getEndAddr() const {
    424     return mEndAddr;
    425 }
    426 
    427 uint64_t VTable::getBaseOffset() const {
    428     return mBaseOffset;
    429 }
    430 
    431 uint64_t VTable::getVTableSize() const {
    432     return mFunctions.size();
    433 }
    434 
    435 VTable::func_iterator VTable::begin() const {
    436     return mFunctions.cbegin();
    437 }
    438 
    439 VTable::func_iterator VTable::end() const {
    440     return mFunctions.cend();
    441 }
    442 
    443 bool VTable::operator<(const VTable &Vtable) const {
    444     return mStartAddr < Vtable.getStartAddr();
    445 }
    446 
    447 bool VTable::operator<(const uint64_t ROffset) const {
    448     return mStartAddr < ROffset;
    449 }
    450 
    451 void VTable::sortVFunctions() {
    452     std::sort(mFunctions.begin(), mFunctions.end());
    453 }
    454