Merge "Remove checkstyle from development/checkstyle."
diff --git a/vndk/Android.bp b/vndk/Android.bp
new file mode 100644
index 0000000..5a94875
--- /dev/null
+++ b/vndk/Android.bp
@@ -0,0 +1,19 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+subdirs = [
+    "tools",
+]
diff --git a/vndk/tools/Android.bp b/vndk/tools/Android.bp
new file mode 100644
index 0000000..c1e9801
--- /dev/null
+++ b/vndk/tools/Android.bp
@@ -0,0 +1,19 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+subdirs = [
+    "abides",
+]
diff --git a/vndk/tools/abides/Android.bp b/vndk/tools/abides/Android.bp
new file mode 100644
index 0000000..cf4c24f
--- /dev/null
+++ b/vndk/tools/abides/Android.bp
@@ -0,0 +1,19 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+subdirs = [
+    "vtable",
+]
diff --git a/vndk/tools/abides/vtable/Android.bp b/vndk/tools/abides/vtable/Android.bp
new file mode 100644
index 0000000..6e0f795
--- /dev/null
+++ b/vndk/tools/abides/vtable/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_defaults {
+    name: "vndk-vtable-defaults",
+
+    defaults: [
+        "clang-defaults",
+    ],
+
+    shared_libs: [
+        "libLLVM",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-std=c++11",
+    ],
+}
+
+cc_binary_host {
+    name: "llvm-figure-out-vtables",
+
+    defaults: [
+        "vndk-vtable-defaults"
+    ],
+
+    srcs: [
+				"llvm_elf_handling.cpp",
+        "llvm_vtable_dump.cpp"],
+}
diff --git a/vndk/tools/abides/vtable/llvm_elf_handling.cpp b/vndk/tools/abides/vtable/llvm_elf_handling.cpp
new file mode 100644
index 0000000..e7adfc3
--- /dev/null
+++ b/vndk/tools/abides/vtable/llvm_elf_handling.cpp
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "llvm_elf_handling.h"
+
+#include <cxxabi.h>
+
+using llvm::ELF::ELFDATA2MSB;
+using llvm::ELF::EM_ARM;
+using llvm::ELF::EM_MIPS;
+using llvm::ELF::R_AARCH64_ABS64;
+using llvm::ELF::R_AARCH64_RELATIVE;
+using llvm::ELF::R_ARM_ABS32;
+using llvm::ELF::R_ARM_RELATIVE;
+using llvm::ELF::R_X86_64_64;
+using llvm::ELF::R_X86_64_RELATIVE;
+using llvm::ELF::R_MIPS_64;
+using llvm::ELF::R_MIPS_REL32;
+using llvm::ELF::R_MIPS_NONE;
+using llvm::ELF::SHT_PROGBITS;
+using llvm::ELF::SHT_REL;
+using llvm::ELF::SHT_RELA;
+using llvm::Expected;
+using llvm::StringRef;
+using llvm::dyn_cast;
+using llvm::object::ELF32BEObjectFile;
+using llvm::object::ELF32LEObjectFile;
+using llvm::object::ELF64BEObjectFile;
+using llvm::object::ELF64LEObjectFile;
+using llvm::object::symbol_iterator;
+using llvm::support::endian::read;
+using llvm::outs;
+using llvm::Error;
+using llvm::make_unique;
+
+static std::string demangle(const std::string &MangledName) {
+     char *Str = __cxxabiv1::__cxa_demangle(
+             MangledName.c_str(),
+             nullptr,
+             0,
+             nullptr);
+     if (Str) {
+         std::string DemangledString(Str);
+         free(Str);
+         return DemangledString;
+     }
+     return "";
+}
+
+SharedObject::~SharedObject() {}
+
+template <typename ELFT>
+static std::unique_ptr<SharedObject> createELFSharedObject(
+        const ELFObjectFile<ELFT> *Objfile) {
+    return make_unique<ELFSharedObject<ELFT>>(Objfile);
+}
+
+static std::unique_ptr<SharedObject>createELFObjFile(const ObjectFile *Obj) {
+    if (const ELF32LEObjectFile *Objfile = dyn_cast<ELF32LEObjectFile>(Obj))
+        return createELFSharedObject(Objfile);
+    if (const ELF32BEObjectFile *Objfile = dyn_cast<ELF32BEObjectFile>(Obj))
+        return createELFSharedObject(Objfile);
+    if (const ELF64LEObjectFile *Objfile = dyn_cast<ELF64LEObjectFile>(Obj))
+        return createELFSharedObject(Objfile);
+    if (const ELF64BEObjectFile *Objfile = dyn_cast<ELF64BEObjectFile>(Obj))
+        return createELFSharedObject(Objfile);
+
+    return nullptr;
+}
+
+std::unique_ptr<SharedObject> SharedObject::create(const ObjectFile *Obj) {
+    std::unique_ptr<SharedObject> res(createELFObjFile(Obj));
+    if (res && res->getVTables()) {
+        return res;
+    }
+    return nullptr;
+}
+
+template <typename ELFT>
+ELFSharedObject<ELFT>::~ELFSharedObject() {}
+
+template <typename ELFT>
+ELFSharedObject<ELFT>::ELFSharedObject(
+        const ELFObjectFile<ELFT> *Objfile)
+    : mObj(Objfile) {}
+
+template <typename ELFT>
+bool ELFSharedObject<ELFT>::cacheELFSections() {
+    for (const SectionRef &ElfSection : mObj->sections()) {
+        const Elf_Shdr *ElfShdr =
+                mObj->getSection(ElfSection.getRawDataRefImpl());
+        if (!ElfShdr) {
+            outs() << "Couldn't create elf shdr \n";
+            return false;
+        }
+        switch (ElfShdr->sh_type) {
+            case SHT_RELA:
+            case SHT_REL:
+                mRelSectionRefs.emplace_back(ElfSection);
+                break;
+            case SHT_PROGBITS:
+                mProgBitSectionRefs.emplace_back(ElfSection);
+                break;
+            default :
+                // Any other section won't have information pertinent
+                // to vtables. Relocation entries will have the virtual
+                // functions' relocation information, the PROGBITS sections
+                // will have the vtables themselves.
+                break;
+        }
+    }
+    return true;
+}
+
+template <typename ELFT>
+void ELFSharedObject<ELFT>::printVTables() const {
+    for (const VTable &Vtable : mVTables) {
+        if (Vtable.getVTableSize() == 0)
+            continue;
+        outs() << Vtable.getDemangledName()
+               << "\n"
+               << Vtable.getMangledName()
+               << ": "
+               << Vtable.getVTableSize()
+               << " entries"
+               << "\n";
+        for (const VFunction &Vfunction : Vtable) {
+            outs() << Vfunction.getOffset()
+                   << "    (int (*)(...)) "
+                   << Vfunction.getDemangledName()
+                   << "\n";
+        }
+        outs() << "\n"
+               << "\n";
+    }
+}
+
+template <typename ELFT>
+bool ELFSharedObject<ELFT>::getVTables() {
+    if (!cacheELFSections()) {
+        return false;
+    }
+    if (!initVTableRanges()) {
+        return true;
+    }
+    getVFunctions();
+    for (VTable &Vtable : mVTables) {
+        // Sort the functions by offset before displaying them since the order
+        // of functions appearing in relocation sections might change. That
+        // should not result in the vtable layout changing.
+        Vtable.sortVFunctions();
+    }
+    return true;
+}
+
+template <typename ELFT>
+bool ELFSharedObject<ELFT>::initVTableRanges() {
+    // Go through all the symbols in the dynsym / symtab sections
+    // and cache all the relevant symbols. i.e: symbols which correspond
+    // to either vtables or functions.
+
+    std::vector<std::pair<SymbolRef, uint64_t>> SymsAndSizes =
+            computeSymbolSizes(*mObj);
+    for (std::pair<SymbolRef, uint64_t> &Pair : SymsAndSizes) {
+        SymbolRef Symbol = Pair.first;
+        SymbolRef::Type SymType = UnWrap(Symbol.getType());
+        uint64_t SymValue = Symbol.getValue();
+        StringRef SymName = UnWrap(Symbol.getName());
+        if (SymName.startswith("__ZTV") || SymName.startswith("_ZTV")) {
+            mVTables.emplace_back(
+                    SymName.str(),
+                    demangle(SymName.str()),
+                    Symbol.getValue(),
+                    Symbol.getValue() + Pair.second);
+        } else if (SymType == SymbolRef::ST_Function) {
+            std::map<uint64_t, std::vector<SymbolRef>>::iterator It =
+                    mAddrToSymbolRef.find(SymValue);
+            if (It == mAddrToSymbolRef.end()) {
+                mAddrToSymbolRef.insert(std::make_pair(
+                        SymValue, std::vector<SymbolRef>(1, Symbol)));
+            } else {
+                std::vector<SymbolRef> &SymVec = It->second;
+                SymVec.emplace_back(Symbol);
+            }
+        }
+    }
+    if (mVTables.size() == 0) {
+        return false;
+    }
+    std::sort(mVTables.begin(), mVTables.end());
+    return true;
+}
+
+template <typename ELFT>
+void ELFSharedObject<ELFT>::getVFunctions() {
+    for (const SectionRef &Section : mRelSectionRefs) {
+        for (const RelocationRef &Relocation : Section.relocations()) {
+            VTable *VtPtr = identifyVTable(Relocation.getOffset());
+            if (VtPtr != nullptr) {
+                relocateSym(Relocation, Section, VtPtr);
+            }
+        }
+    }
+}
+
+template <typename ELFT>
+VTable *ELFSharedObject<ELFT>::identifyVTable(uint64_t RelOffset) {
+    typename std::vector<VTable>::iterator It;
+    It = std::lower_bound(mVTables.begin(), mVTables.end(), RelOffset);
+    if (It != mVTables.begin() && It->getStartAddr() != RelOffset) {
+        It--;
+    }
+    if (It->getEndAddr() >= RelOffset) {
+        return &(*It);
+    }
+    return nullptr;
+}
+
+template <typename ELFT>
+void ELFSharedObject<ELFT>::relocateSym(
+        const RelocationRef &Relocation,
+        const SectionRef &Section,
+        VTable *Vtablep) {
+    const Elf_Ehdr *ElfHeader = mObj->getELFFile()->getHeader();
+    if (ElfHeader->e_machine == EM_MIPS) {
+        // bionic/linker/linker_mips.cpp , we handle only one type of
+        // relocation. Depending on if the symbol can be inferred from r_info we
+        // make it an absolute or a relative relocation.
+        if (!absoluteRelocation(Relocation, Vtablep)) {
+            relativeRelocation(Relocation, Section, Vtablep);
+        }
+    } else {
+        switch(Relocation.getType()) {
+            case R_AARCH64_RELATIVE:
+            case R_X86_64_RELATIVE:
+            case R_ARM_RELATIVE:
+            {
+                // The return value is ignored since failure to relocate
+                // does not mean a fatal error. It might be that the dynsym /
+                // symbol-table does not have enough information to get the
+                // symbol name. Like-wise for absolute relocations.
+                relativeRelocation(Relocation, Section, Vtablep);
+                break;
+            }
+            case R_AARCH64_ABS64:
+            case R_X86_64_64:
+            case R_ARM_ABS32:
+            {
+                absoluteRelocation(Relocation, Vtablep);
+                break;
+            }
+            default:
+                break;
+        }
+    }
+}
+
+template <typename ELFT>
+bool ELFSharedObject<ELFT>::absoluteRelocation(
+        const RelocationRef &Relocation,
+        VTable *Vtablep) {
+    symbol_iterator Symi = Relocation.getSymbol();
+    if (Symi == mObj->symbol_end()) {
+        return false;
+    }
+    SymbolRef Symbol = *Symi;
+    uint64_t RelOffset = Relocation.getOffset();
+    StringRef SymbolName = UnWrap(Symbol.getName());
+    std::string DemangledName = demangle(SymbolName.str());
+    if (!DemangledName.empty()) {
+        Vtablep->addVFunction(SymbolName.str(), DemangledName, RelOffset);
+        return true;
+    }
+    return false;
+}
+
+template <typename ELFT>
+bool ELFSharedObject<ELFT>::relativeRelocation(
+        const RelocationRef &Relocation,
+        const SectionRef &Section,
+        VTable *Vtablep) {
+    uint64_t Addend = 0;
+    uint64_t RelOffset = Relocation.getOffset();
+    if (mObj->getSection(Section.getRawDataRefImpl())->sh_type == SHT_RELA) {
+        const Elf_Rela *Rela = mObj->getRela(Relocation.getRawDataRefImpl());
+        Addend = static_cast<uint64_t>(Rela->r_addend);
+    }
+
+    if (Addend == 0) {
+        Addend = identifyAddend(Relocation.getOffset());
+    }
+
+    std::map<uint64_t, std::vector<SymbolRef>>::iterator It =
+            mAddrToSymbolRef.find(Addend);
+    if (It == mAddrToSymbolRef.end()) {
+        return false;
+    }
+    SymbolRef Symbol = matchValueToSymbol(It->second, Vtablep);
+    StringRef SymbolName = UnWrap(Symbol.getName());
+    std::string DemangledName = demangle(SymbolName.str());
+    if (!DemangledName.empty()) {
+        Vtablep->addVFunction(SymbolName.str(), DemangledName, RelOffset);
+        return true;
+    }
+    return false;
+}
+
+template <typename ELFT>
+SymbolRef ELFSharedObject<ELFT>::matchValueToSymbol(
+        std::vector<SymbolRef> &SymVec,
+        VTable *Vtablep) {
+    constexpr size_t pos = sizeof("vtable for ") - 1;
+    const std::string ClassName(Vtablep->getDemangledName().substr(pos));
+    for (const SymbolRef &Symbol : SymVec) {
+        StringRef SymbolName = UnWrap(Symbol.getName());
+        if (SymbolName.str().find(ClassName) != std::string::npos)
+            return Symbol;
+    }
+    // Return the 1st Symbol by default.
+    return SymVec[0];
+}
+
+template <typename ELFT>
+uint64_t ELFSharedObject<ELFT>::identifyAddend(uint64_t ROffset) {
+    for (const SectionRef &Section : mProgBitSectionRefs) {
+        uint64_t Begin = Section.getAddress();
+        uint64_t End = Section.getAddress() + Section.getSize();
+        if (ROffset >= Begin && ROffset <= End) {
+            return getAddendFromSection(Section, ROffset - Begin);
+        }
+    }
+    return 0;
+}
+
+template <typename ELFT>
+uint64_t ELFSharedObject<ELFT>::getAddendFromSection(
+        const SectionRef &Section,
+        uint64_t Offset) {
+    StringRef Contents;
+    if (Section.getContents(Contents))
+        return 0;
+    const unsigned char *Bytes = Contents.bytes_begin() + Offset;
+    uintX_t Addend = read<uintX_t, ELFT::TargetEndianness>(Bytes);
+    const Elf_Ehdr *ElfHeader = mObj->getELFFile()->getHeader();
+    if (ElfHeader->e_machine == EM_ARM ||
+        ElfHeader->e_machine == EM_MIPS) {
+        // Remove thumb flag as llvm suggests.
+        Addend &= ~1;
+    }
+    return static_cast<uint64_t>(Addend);
+}
+
+VFunction::VFunction(
+        const std::string &MangledName,
+        const std::string &DemangledName,
+        uint64_t VFunctionOffset)
+    : mMangledName(MangledName),
+      mDemangledName(DemangledName),
+      mOffset(VFunctionOffset) {}
+
+uint64_t VFunction::getOffset() const {
+    return mOffset;
+}
+
+const std::string &VFunction::getDemangledName() const {
+    return mDemangledName;
+}
+
+const std::string &VFunction::getMangledName() const {
+    return mMangledName;
+}
+
+bool VFunction::operator<(const VFunction &Vfunction) const {
+    return mOffset < Vfunction.getOffset();
+}
+
+VTable::VTable(
+        const std::string &MangledName,
+        const std::string &DemangledName,
+        uint64_t Begin,
+        uint64_t End)
+    : mMangledName(MangledName),
+      mDemangledName(DemangledName),
+      mStartAddr(Begin),
+      mEndAddr(End),
+      mBaseOffset(Begin) {}
+
+void VTable::addVFunction(
+        const std::string &MangledName,
+        const std::string &DemangledName,
+        uint64_t RelOffset) {
+    mFunctions.emplace_back(
+            MangledName,
+            DemangledName,
+            RelOffset - mBaseOffset);
+}
+
+const std::string &VTable::getDemangledName() const {
+    return mDemangledName;
+}
+
+const std::string &VTable::getMangledName() const {
+    return mMangledName;
+}
+
+uint64_t VTable::getStartAddr() const {
+    return mStartAddr;
+}
+
+uint64_t VTable::getEndAddr() const {
+    return mEndAddr;
+}
+
+uint64_t VTable::getBaseOffset() const {
+    return mBaseOffset;
+}
+
+uint64_t VTable::getVTableSize() const {
+    return mFunctions.size();
+}
+
+VTable::func_iterator VTable::begin() const {
+    return mFunctions.cbegin();
+}
+
+VTable::func_iterator VTable::end() const {
+    return mFunctions.cend();
+}
+
+bool VTable::operator<(const VTable &Vtable) const {
+    return mStartAddr < Vtable.getStartAddr();
+}
+
+bool VTable::operator<(const uint64_t ROffset) const {
+    return mStartAddr < ROffset;
+}
+
+void VTable::sortVFunctions() {
+    std::sort(mFunctions.begin(), mFunctions.end());
+}
diff --git a/vndk/tools/abides/vtable/llvm_elf_handling.h b/vndk/tools/abides/vtable/llvm_elf_handling.h
new file mode 100644
index 0000000..25ee6ca
--- /dev/null
+++ b/vndk/tools/abides/vtable/llvm_elf_handling.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ELF_HANDLING_H_
+#define ELF_HANDLING_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+#include <llvm/Object/ELFObjectFile.h>
+#include <llvm/Object/ELFTypes.h>
+#include <llvm/Object/SymbolSize.h>
+#include <llvm/Support/Endian.h>
+#include <llvm/Support/raw_ostream.h>
+
+using llvm::object::ObjectFile;
+using llvm::object::ELFObjectFile;
+using llvm::object::SectionRef;
+using llvm::object::RelocationRef;
+using llvm::object::ELFFile;
+using llvm::object::ELFType;
+using llvm::object::ELFDataTypeTypedefHelper;
+using llvm::object::SymbolRef;
+using llvm::outs;
+
+class SharedObject {
+public:
+    static std::unique_ptr<SharedObject> create(const ObjectFile *);
+    virtual void printVTables() const = 0;
+    virtual ~SharedObject() = 0;
+private:
+    virtual bool getVTables() = 0;
+};
+
+class VFunction {
+public:
+    VFunction(
+            const std::string &,
+            const std::string &,
+            uint64_t);
+
+    uint64_t getOffset() const;
+    bool operator<(const VFunction &) const;
+    const std::string &getMangledName() const;
+    const std::string &getDemangledName() const;
+private:
+    std::string mMangledName;
+    std::string mDemangledName;
+    uint64_t mOffset;
+};
+
+class VTable {
+public:
+    using func_iterator = std::vector<VFunction>::const_iterator;
+    VTable(
+            const std::string &,
+            const std::string &,
+            uint64_t,
+            uint64_t);
+
+    uint64_t getStartAddr() const;
+    uint64_t getEndAddr() const;
+    uint64_t getBaseOffset() const;
+    uint64_t getVTableSize() const;
+    func_iterator begin() const;
+    func_iterator end() const;
+    const std::string &getMangledName() const;
+    const std::string &getDemangledName() const;
+    void sortVFunctions();
+    void addVFunction(
+            const std::string &,
+            const std::string &,
+            uint64_t);
+
+    bool operator<(const VTable &) const;
+    bool operator<(const uint64_t) const;
+private:
+    std::vector<VFunction> mFunctions;
+    std::string mMangledName;
+    std::string mDemangledName;
+    /* This holds the range(st_value, st_value) through which the
+     * VTable spans.
+     */
+    uint64_t mStartAddr;
+    uint64_t mEndAddr;
+    uint64_t mBaseOffset;
+};
+
+template<typename ELFT>
+class ELFSharedObject : public SharedObject {
+public:
+    void printVTables() const override;
+    bool getVTables() override;
+    ~ELFSharedObject();
+    ELFSharedObject(const ELFObjectFile<ELFT> *);
+
+private:
+    /* We need a sym value to SymbolRef map in case the relocation provides
+     * us with an addr instead of a sym index into dynsym / symtab.
+     */
+    LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+    typedef ELFFile<ELFT> ELFO;
+    typedef typename ELFO::Elf_Shdr Elf_Shdr;
+    typedef typename ELFO::Elf_Ehdr Elf_Ehdr;
+    typedef typename ELFO::Elf_Sym Elf_Sym;
+    typedef typename ELFO::Elf_Rela Elf_Rela;
+    typedef typename ELFO::uintX_t uintX_t;
+    std::map<uint64_t, std::vector<SymbolRef>> mAddrToSymbolRef;
+    const ELFObjectFile<ELFT> *mObj;
+    /* We cache the relocation sections, to look through their relocations for
+     * vfunctions. Sections with type SHT_PROGBITS are cached since they contain
+     * vtables. We might need to peek at the contents of a vtable in cases of
+     * relative relocations.
+     */
+    std::vector<SectionRef> mRelSectionRefs;
+    std::vector<SectionRef> mProgBitSectionRefs;
+    std::vector<VTable> mVTables;
+
+private:
+    bool cacheELFSections();
+    bool initVTableRanges();
+    void getVFunctions();
+    VTable *identifyVTable(uint64_t);
+    void relocateSym(
+            const RelocationRef &,
+            const SectionRef &,
+            VTable *);
+
+    bool absoluteRelocation(const RelocationRef &, VTable *);
+    bool relativeRelocation(
+            const RelocationRef &,
+            const SectionRef &,
+            VTable *);
+
+    uint64_t identifyAddend(uint64_t);
+    uint64_t getAddendFromSection(const SectionRef &, uint64_t);
+    SymbolRef matchValueToSymbol(std::vector<SymbolRef> &, VTable *);
+};
+
+template <typename T>
+static inline T UnWrap(llvm::Expected<T> ValueOrError) {
+    if (!ValueOrError) {
+        outs() << "\nError: "
+               << llvm::toString(ValueOrError.takeError())
+               << ".\n";
+        outs().flush();
+        exit(1);
+    }
+    return std::move(ValueOrError.get());
+}
+
+
+#endif  // ELF_HANDLING_H_
+
diff --git a/vndk/tools/abides/vtable/llvm_vtable_dump.cpp b/vndk/tools/abides/vtable/llvm_vtable_dump.cpp
new file mode 100644
index 0000000..fcbf793
--- /dev/null
+++ b/vndk/tools/abides/vtable/llvm_vtable_dump.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "llvm_elf_handling.h"
+
+using llvm::Expected;
+using llvm::StringRef;
+using llvm::dyn_cast;
+using llvm::object::ObjectFile;
+using llvm::object::OwningBinary;
+using llvm::outs;
+
+int main (int argc, char **argv)
+{
+    if (argc != 2) {
+        outs() << "usage: figure-out-vtables path \n";
+        return 1;
+    }
+    Expected<OwningBinary<ObjectFile>> Binary =
+            ObjectFile::createObjectFile(StringRef(argv[1]));
+    if (!Binary) {
+        outs() << "Couldn't create object File \n";
+        return 1;
+    }
+    ObjectFile *Objfile = dyn_cast<ObjectFile>(&(*Binary.get().getBinary()));
+    if (!Objfile) {
+        return 1;
+    }
+    auto SoFile = SharedObject::create(Objfile);
+    if (!SoFile) {
+        outs() << "Couldn't create ELFObjectFile \n";
+        return 1;
+    }
+    SoFile->printVTables();
+    return 0;
+}
diff --git a/vndk/tools/abides/vtable/test/expected/arm/libtest.so.txt b/vndk/tools/abides/vtable/test/expected/arm/libtest.so.txt
new file mode 100644
index 0000000..24b0126
--- /dev/null
+++ b/vndk/tools/abides/vtable/test/expected/arm/libtest.so.txt
@@ -0,0 +1,21 @@
+vtable for Alpha
+_ZTV5Alpha: 3 entries
+8    (int (*)(...)) Alpha::getData(int*, int*, int)
+12    (int (*)(...)) Alpha::~Alpha()
+16    (int (*)(...)) Alpha::~Alpha()
+
+
+vtable for Beta
+_ZTV4Beta: 3 entries
+8    (int (*)(...)) Beta::getData(int*, int*, int)
+12    (int (*)(...)) Beta::~Beta()
+16    (int (*)(...)) Beta::~Beta()
+
+
+vtable for Gamma
+_ZTV5Gamma: 3 entries
+8    (int (*)(...)) Gamma::getData(int*, int*, int)
+12    (int (*)(...)) Gamma::~Gamma()
+16    (int (*)(...)) Gamma::~Gamma()
+
+
diff --git a/vndk/tools/abides/vtable/test/expected/arm64/libtest.so.txt b/vndk/tools/abides/vtable/test/expected/arm64/libtest.so.txt
new file mode 100644
index 0000000..5a0ea37
--- /dev/null
+++ b/vndk/tools/abides/vtable/test/expected/arm64/libtest.so.txt
@@ -0,0 +1,21 @@
+vtable for Alpha
+_ZTV5Alpha: 3 entries
+16    (int (*)(...)) Alpha::getData(int*, int*, int)
+24    (int (*)(...)) Alpha::~Alpha()
+32    (int (*)(...)) Alpha::~Alpha()
+
+
+vtable for Beta
+_ZTV4Beta: 3 entries
+16    (int (*)(...)) Beta::getData(int*, int*, int)
+24    (int (*)(...)) Beta::~Beta()
+32    (int (*)(...)) Beta::~Beta()
+
+
+vtable for Gamma
+_ZTV5Gamma: 3 entries
+16    (int (*)(...)) Gamma::getData(int*, int*, int)
+24    (int (*)(...)) Gamma::~Gamma()
+32    (int (*)(...)) Gamma::~Gamma()
+
+
diff --git a/vndk/tools/abides/vtable/test/expected/mips/libtest.so.txt b/vndk/tools/abides/vtable/test/expected/mips/libtest.so.txt
new file mode 100644
index 0000000..24b0126
--- /dev/null
+++ b/vndk/tools/abides/vtable/test/expected/mips/libtest.so.txt
@@ -0,0 +1,21 @@
+vtable for Alpha
+_ZTV5Alpha: 3 entries
+8    (int (*)(...)) Alpha::getData(int*, int*, int)
+12    (int (*)(...)) Alpha::~Alpha()
+16    (int (*)(...)) Alpha::~Alpha()
+
+
+vtable for Beta
+_ZTV4Beta: 3 entries
+8    (int (*)(...)) Beta::getData(int*, int*, int)
+12    (int (*)(...)) Beta::~Beta()
+16    (int (*)(...)) Beta::~Beta()
+
+
+vtable for Gamma
+_ZTV5Gamma: 3 entries
+8    (int (*)(...)) Gamma::getData(int*, int*, int)
+12    (int (*)(...)) Gamma::~Gamma()
+16    (int (*)(...)) Gamma::~Gamma()
+
+
diff --git a/vndk/tools/abides/vtable/test/expected/mips64/libtest.so.txt b/vndk/tools/abides/vtable/test/expected/mips64/libtest.so.txt
new file mode 100644
index 0000000..5a0ea37
--- /dev/null
+++ b/vndk/tools/abides/vtable/test/expected/mips64/libtest.so.txt
@@ -0,0 +1,21 @@
+vtable for Alpha
+_ZTV5Alpha: 3 entries
+16    (int (*)(...)) Alpha::getData(int*, int*, int)
+24    (int (*)(...)) Alpha::~Alpha()
+32    (int (*)(...)) Alpha::~Alpha()
+
+
+vtable for Beta
+_ZTV4Beta: 3 entries
+16    (int (*)(...)) Beta::getData(int*, int*, int)
+24    (int (*)(...)) Beta::~Beta()
+32    (int (*)(...)) Beta::~Beta()
+
+
+vtable for Gamma
+_ZTV5Gamma: 3 entries
+16    (int (*)(...)) Gamma::getData(int*, int*, int)
+24    (int (*)(...)) Gamma::~Gamma()
+32    (int (*)(...)) Gamma::~Gamma()
+
+
diff --git a/vndk/tools/abides/vtable/test/expected/x86/libtest.so.txt b/vndk/tools/abides/vtable/test/expected/x86/libtest.so.txt
new file mode 100644
index 0000000..24b0126
--- /dev/null
+++ b/vndk/tools/abides/vtable/test/expected/x86/libtest.so.txt
@@ -0,0 +1,21 @@
+vtable for Alpha
+_ZTV5Alpha: 3 entries
+8    (int (*)(...)) Alpha::getData(int*, int*, int)
+12    (int (*)(...)) Alpha::~Alpha()
+16    (int (*)(...)) Alpha::~Alpha()
+
+
+vtable for Beta
+_ZTV4Beta: 3 entries
+8    (int (*)(...)) Beta::getData(int*, int*, int)
+12    (int (*)(...)) Beta::~Beta()
+16    (int (*)(...)) Beta::~Beta()
+
+
+vtable for Gamma
+_ZTV5Gamma: 3 entries
+8    (int (*)(...)) Gamma::getData(int*, int*, int)
+12    (int (*)(...)) Gamma::~Gamma()
+16    (int (*)(...)) Gamma::~Gamma()
+
+
diff --git a/vndk/tools/abides/vtable/test/expected/x86_64/libtest.so.txt b/vndk/tools/abides/vtable/test/expected/x86_64/libtest.so.txt
new file mode 100644
index 0000000..5a0ea37
--- /dev/null
+++ b/vndk/tools/abides/vtable/test/expected/x86_64/libtest.so.txt
@@ -0,0 +1,21 @@
+vtable for Alpha
+_ZTV5Alpha: 3 entries
+16    (int (*)(...)) Alpha::getData(int*, int*, int)
+24    (int (*)(...)) Alpha::~Alpha()
+32    (int (*)(...)) Alpha::~Alpha()
+
+
+vtable for Beta
+_ZTV4Beta: 3 entries
+16    (int (*)(...)) Beta::getData(int*, int*, int)
+24    (int (*)(...)) Beta::~Beta()
+32    (int (*)(...)) Beta::~Beta()
+
+
+vtable for Gamma
+_ZTV5Gamma: 3 entries
+16    (int (*)(...)) Gamma::getData(int*, int*, int)
+24    (int (*)(...)) Gamma::~Gamma()
+32    (int (*)(...)) Gamma::~Gamma()
+
+
diff --git a/vndk/tools/abides/vtable/test/test1.cpp b/vndk/tools/abides/vtable/test/test1.cpp
new file mode 100644
index 0000000..606cd98
--- /dev/null
+++ b/vndk/tools/abides/vtable/test/test1.cpp
@@ -0,0 +1,32 @@
+class Alpha {
+public:
+    virtual void getData(int *src, int *dst, int data);
+    virtual ~Alpha() {};
+private:
+    int mPdata = 0;
+};
+
+class Beta : public Alpha {
+public:
+    Beta(int data) : mCdata(data) {}
+    virtual void getData(int *src, int *dst, int data);
+    virtual ~Beta() {};
+private:
+    int mCdata = 1;
+};
+
+class Gamma : public Beta {
+public:
+    Gamma(int data) : mGCdata(data), Beta(data) {}
+    virtual void getData(int *src, int *dst, int data);
+    virtual ~Gamma() {};
+private:
+    int mGCdata = 2;
+};
+
+void Alpha::getData(int *src, int *dst, int data) {}
+
+void Beta::getData(int *src, int *dst, int data) {}
+
+void Gamma::getData(int *src, int *dst, int data) {}
+
diff --git a/vndk/tools/abides/vtable/test/test_vtable.py b/vndk/tools/abides/vtable/test/test_vtable.py
new file mode 100755
index 0000000..048e8fa
--- /dev/null
+++ b/vndk/tools/abides/vtable/test/test_vtable.py
@@ -0,0 +1,267 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import collections
+import difflib
+import os
+import subprocess
+import sys
+import tempfile
+
+"""Test vndk vtable dumper"""
+
+NDK_VERSION = 'r11'
+API_LEVEL = 'android-24'
+
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+VNDK_VTABLE_DUMP = os.path.join('llvm-figure-out-vtables')
+
+def get_dirnames(path, n):
+    """Get directory, n directories before path"""
+    for i in range(n):
+        path = os.path.dirname(path)
+    return path
+
+
+def get_prebuilts_host():
+    """Get the host dir for prebuilts"""
+    if sys.platform.startswith('linux'):
+        return 'linux-x86'
+    if sys.platform.startswith('darwin'):
+        return 'darwin-x86'
+    raise NotImplementedError('unknown platform')
+
+
+def get_prebuilts_gcc(android_build_top, arch, gcc_version):
+    """Get the path to gcc for the current platform"""
+    return os.path.join(android_build_top, 'prebuilts', 'gcc',
+                        get_prebuilts_host(), arch, gcc_version)
+
+def get_prebuilts_clang(android_build_top):
+    """Get the path to prebuilt gcc for the current platform"""
+    return os.path.join(android_build_top, 'prebuilts', 'clang', 'host',
+                        get_prebuilts_host(), 'clang-stable')
+
+def get_prebuilts_ndk(android_build_top, subdirs):
+    """Get the path to prebuilt ndk  for the current platform and API level"""
+    return os.path.join(android_build_top, 'prebuilts', 'ndk', NDK_VERSION,
+                        'platforms', API_LEVEL, *subdirs)
+
+def run_cmd(cmd, verbose=False):
+    """Run the command given and print the command if verbose is True"""
+    if verbose:
+        print('RUN:', ' '.join(cmd), file=sys.stderr)
+    subprocess.check_call(cmd)
+
+
+def run_output(cmd, verbose=False):
+    """Run the command given and print output of the command"""
+    if verbose:
+        print('RUN:', ' '.join(cmd), file=sys.stderr)
+    return subprocess.check_output(cmd, universal_newlines=True)
+
+
+def run_vtable_dump(path, verbose=False):
+    """Run vndk vtable dumper"""
+    return run_output([VNDK_VTABLE_DUMP, path], verbose)
+
+
+class Target(object):
+    """Class representing a target: for eg: x86, arm64 etc"""
+    def __init__(self, name, triple, cflags, ldflags, gcc_toolchain_dir,
+                 clang_dir, ndk_include, ndk_lib):
+        """Parameterized Constructor"""
+        self.name = name
+        self.target_triple = triple
+        self.target_cflags = cflags
+        self.target_ldflags = ldflags
+
+        self.gcc_toolchain_dir = gcc_toolchain_dir
+        self.clang_dir = clang_dir
+        self.ndk_include = ndk_include
+        self.ndk_lib = ndk_lib
+
+    def compile(self, obj_file, src_file, cflags, verbose=False):
+        """Compiles the given source files and produces a .o at obj_file"""
+        clangpp = os.path.join(self.clang_dir, 'bin', 'clang++')
+
+        cmd = [clangpp, '-o', obj_file, '-c', src_file]
+        cmd.extend(['-fPIE', '-fPIC', '-fno-rtti', '-std=c++11'])
+        cmd.extend(['-gcc-toolchain', self.gcc_toolchain_dir])
+        cmd.extend(['-target', self.target_triple])
+        cmd.extend(['-isystem', self.ndk_include])
+        cmd.extend(cflags)
+        cmd.extend(self.target_cflags)
+        run_cmd(cmd, verbose)
+
+    def link(self, out_file, obj_files, ldflags, verbose=False):
+        """Link the given obj files to form a shared library"""
+        crtbegin = os.path.join(self.ndk_lib, 'crtbegin_so.o')
+        crtend = os.path.join(self.ndk_lib, 'crtend_so.o')
+        clangpp = os.path.join(self.clang_dir, 'bin', 'clang++')
+
+        cmd = [clangpp, '-o', out_file]
+        cmd.extend(['-fPIE', '-fPIC', '-fno-rtti', '-Wl,--no-undefined', '-nostdlib'])
+        cmd.append('-L' + self.ndk_lib)
+        cmd.extend(['-gcc-toolchain', self.gcc_toolchain_dir])
+        cmd.extend(['-target', self.target_triple])
+        cmd.append(crtbegin)
+        cmd.extend(obj_files)
+        cmd.append(crtend)
+        cmd.extend(ldflags)
+        cmd.extend(self.target_ldflags)
+        run_cmd(cmd, verbose)
+
+
+def create_targets(top):
+    """Create multiple targets objects, one for each architecture supported"""
+    return [
+        Target('arm', 'arm-linux-androideabi', [],[],
+               get_prebuilts_gcc(top, 'arm', 'arm-linux-androideabi-4.9'),
+               get_prebuilts_clang(top),
+               get_prebuilts_ndk(top, ['arch-arm', 'usr', 'include']),
+               get_prebuilts_ndk(top, ['arch-arm', 'usr', 'lib'])),
+
+        Target('arm64', 'aarch64-linux-android', [], [],
+               get_prebuilts_gcc(top, 'aarch64', 'aarch64-linux-android-4.9'),
+               get_prebuilts_clang(top),
+               get_prebuilts_ndk(top, ['arch-arm64', 'usr', 'include']),
+               get_prebuilts_ndk(top, ['arch-arm64', 'usr', 'lib'])),
+
+        Target('mips', 'mipsel-linux-android', [], [],
+               get_prebuilts_gcc(top, 'mips', 'mips64el-linux-android-4.9'),
+               get_prebuilts_clang(top),
+               get_prebuilts_ndk(top, ['arch-mips', 'usr', 'include']),
+               get_prebuilts_ndk(top, ['arch-mips', 'usr', 'lib'])),
+
+        Target('mips64', 'mips64el-linux-android',
+               ['-march=mips64el', '-mcpu=mips64r6'],
+               ['-march=mips64el', '-mcpu=mips64r6'],
+               get_prebuilts_gcc(top, 'mips', 'mips64el-linux-android-4.9'),
+               get_prebuilts_clang(top),
+               get_prebuilts_ndk(top, ['arch-mips64', 'usr', 'include']),
+               get_prebuilts_ndk(top, ['arch-mips64', 'usr', 'lib64'])),
+
+        Target('x86', 'x86_64-linux-android', ['-m32'], ['-m32'],
+               get_prebuilts_gcc(top, 'x86', 'x86_64-linux-android-4.9'),
+               get_prebuilts_clang(top),
+               get_prebuilts_ndk(top, ['arch-x86', 'usr', 'include']),
+               get_prebuilts_ndk(top, ['arch-x86', 'usr', 'lib'])),
+
+        Target('x86_64', 'x86_64-linux-android', ['-m64'], ['-m64'],
+               get_prebuilts_gcc(top, 'x86', 'x86_64-linux-android-4.9'),
+               get_prebuilts_clang(top),
+               get_prebuilts_ndk(top, ['arch-x86_64', 'usr', 'include']),
+               get_prebuilts_ndk(top, ['arch-x86_64', 'usr', 'lib64'])),
+    ]
+
+
+class TestRunner(object):
+    """Class to run the test"""
+    def __init__(self, expected_dir, test_dir, verbose):
+        """Parameterized constructor"""
+        self.expected_dir = expected_dir
+        self.test_dir = test_dir
+        self.verbose = verbose
+        self.num_errors = 0
+
+    def check_output(self, expected_file_path, actual):
+        """Compare the output of the test run and the expected output"""
+        actual = actual.splitlines(True)
+        with open(expected_file_path, 'r') as f:
+            expected = f.readlines()
+        if actual == expected:
+            return
+        for line in difflib.context_diff(expected, actual,
+                                         fromfile=expected_file_path,
+                                         tofile='actual'):
+            sys.stderr.write(line)
+        self.num_errors += 1
+
+    def run_test_for_target(self, target):
+        """Run the test for a specific target"""
+        print('Testing target', target.name, '...', file=sys.stderr)
+
+        expected_dir = os.path.join(self.expected_dir, target.name)
+
+        # Create test directory for this target.
+        test_dir = os.path.join(self.test_dir, target.name)
+        os.makedirs(test_dir, exist_ok=True)
+
+        # Compile and test "libtest.so".
+        src_file = os.path.join(SCRIPT_DIR, 'test1.cpp')
+        obj_file = os.path.join(test_dir, 'test.o')
+        target.compile(obj_file, src_file, [], self.verbose)
+
+        out_file = os.path.join(test_dir, 'libtest.so')
+        target.link(out_file, [obj_file],
+                    ['-shared', '-lc', '-lgcc', '-lstdc++'],
+                    self.verbose)
+        self.check_output(os.path.join(expected_dir, 'libtest.so.txt'),
+                          run_vtable_dump(out_file, self.verbose))
+
+    def run_test(self, targets):
+        """Run test fo all targets"""
+        for target in targets:
+            self.run_test_for_target(target)
+
+
+def main():
+    """ Set up and run test"""
+    # Parse command line arguments.
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--verbose', '-v', action='store_true')
+    parser.add_argument('--android-build-top', help='path to android build top')
+    parser.add_argument('--test-dir',
+                        help='directory for temporary files')
+    parser.add_argument('--expected-dir', help='directory with expected output')
+    args = parser.parse_args()
+
+    # Find ${ANDROID_BUILD_TOP}.
+    if args.android_build_top:
+        android_build_top = args.android_build_top
+    else:
+        android_build_top = get_dirnames(SCRIPT_DIR, 6)
+
+    # Find expected output directory.
+    if args.expected_dir:
+        expected_dir = args.expected_dir
+    else:
+        expected_dir = os.path.join(SCRIPT_DIR, 'expected')
+
+    # Load compilation targets.
+    targets = create_targets(android_build_top)
+
+    # Run tests.
+    if args.test_dir:
+        os.makedirs(args.test_dir, exist_ok=True)
+        runner = TestRunner(expected_dir, args.test_dir, args.verbose)
+        runner.run_test(targets)
+    else:
+        with tempfile.TemporaryDirectory() as test_dir:
+            runner = TestRunner(expected_dir, test_dir, args.verbose)
+            runner.run_test(targets)
+
+    if runner.num_errors:
+        print('FAILED:', runner.num_errors, 'test(s) failed', file=sys.stderr)
+    else:
+        print('SUCCESS', file=sys.stderr)
+
+    return 1 if runner.num_errors else 0
+
+if __name__ == '__main__':
+    sys.exit(main())