Merge changes I0d65bcdc,I7499691c

* changes:
  vndk-def: Generalize FWK-ONLY-RS / VNDK-SP
  vndk-def: Support Treble VNDK directory layout
diff --git a/vndk/tools/header-checker/Android.bp b/vndk/tools/header-checker/Android.bp
index 71cf175..3f29d06 100644
--- a/vndk/tools/header-checker/Android.bp
+++ b/vndk/tools/header-checker/Android.bp
@@ -24,11 +24,14 @@
     cflags: [
         "-Wall",
         "-Werror",
-        "-std=c++11",
         "-DGOOGLE_PROTOBUF_NO_RTTI",
         "-UNDEBUG"
     ],
 
+    cppflags: [
+        "-std=c++14",
+    ],
+
     target: {
         windows: {
             enabled: false
@@ -40,8 +43,8 @@
     name: "header-checker-lib-defaults",
 
     static_libs: [
-        "libclangTooling",
         "libclangToolingCore",
+        "libclangTooling",
         "libclangFrontendTool",
         "libclangFrontend",
         "libclangDriver",
@@ -134,8 +137,8 @@
     ],
 
     static_libs: [
-        "libheader-checker-proto",
         "libheader-abi-util",
+        "libheader-checker-proto",
     ],
 
     target: {
@@ -269,8 +272,14 @@
         "libLLVMMCParser",
         "libLLVMCore",
         "libLLVMSupport",
+        "libheader-checker-proto",
     ],
 
+    shared_libs: [
+        "libprotobuf-cpp-full",
+    ],
+
+
     cflags: [
         "-Wcast-qual",
         "-Wno-long-long",
diff --git a/vndk/tools/header-checker/README.md b/vndk/tools/header-checker/README.md
index 9412f60..242786a 100644
--- a/vndk/tools/header-checker/README.md
+++ b/vndk/tools/header-checker/README.md
@@ -7,6 +7,7 @@
 ## Usage
  header-abi-dumper -o <dump-file> <source_file> -I <export-include-dir-1> -I
  <export-include-dir-2>.. -- <cflags>
+ For options : header-abi-dumper --help
 
 # VNDK Header Abi Linker
 
@@ -16,6 +17,7 @@
 
 ## Usage
  header-abi-linker -o <linked-abi-dump> <abi-dump1> <abi-dump2> <abi-dump3> ...
+ For options : header-abi-linker --help
 
 # VNDK Header Abi Diff
 
@@ -24,10 +26,13 @@
  abi's exposed by the two dumps.
 
 # Return Value
- 1: InCompatible
- 0: Compatible or Compatible Extension.
+ 0: Compatible
+ 1: Changes to APIs unreferenced by symbols in the .dynsym table
+ 4: Compatible Extension
+ 8: Incompatible
 
 
 ## Usage
  header-abi-diff -old <old-abi-dump> -new <new-abi-dump> -o <report>
+ For options : header-abi-diff --help
 
diff --git a/vndk/tools/header-checker/header-abi-diff/src/abi_diff.cpp b/vndk/tools/header-checker/header-abi-diff/src/abi_diff.cpp
index 45aac64..7d21566 100644
--- a/vndk/tools/header-checker/header-abi-diff/src/abi_diff.cpp
+++ b/vndk/tools/header-checker/header-abi-diff/src/abi_diff.cpp
@@ -14,169 +14,262 @@
 
 #include "abi_diff.h"
 
+#include <header_abi_util.h>
+
 #include <llvm/Support/raw_ostream.h>
 
 #include <google/protobuf/text_format.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
 
 #include <memory>
-#include <fstream>
-#include <iostream>
 #include <string>
 #include <vector>
 
 #include <stdlib.h>
 
-CompatibilityStatus HeaderAbiDiff::GenerateCompatibilityReport() {
-  abi_dump::TranslationUnit old_tu;
-  abi_dump::TranslationUnit new_tu;
-  std::ifstream old_input(old_dump_);
-  std::ifstream new_input(new_dump_);
-  google::protobuf::io::IstreamInputStream text_iso(&old_input);
-  google::protobuf::io::IstreamInputStream text_isn(&new_input);
-
-  if (!google::protobuf::TextFormat::Parse(&text_iso, &old_tu) ||
-      !google::protobuf::TextFormat::Parse(&text_isn, &new_tu)) {
-    llvm::errs() << "Failed to generate compatibility report\n";
+abi_util::CompatibilityStatusIR HeaderAbiDiff::GenerateCompatibilityReport() {
+  using abi_util::TextFormatToIRReader;
+  std::unique_ptr<abi_util::TextFormatToIRReader> old_reader =
+      TextFormatToIRReader::CreateTextFormatToIRReader("protobuf", old_dump_);
+  std::unique_ptr<abi_util::TextFormatToIRReader> new_reader =
+      TextFormatToIRReader::CreateTextFormatToIRReader("protobuf", new_dump_);
+  if (!old_reader || !new_reader || !old_reader->ReadDump() ||
+      !new_reader->ReadDump()) {
+    llvm::errs() << "Could not create Text Format readers\n";
     ::exit(1);
   }
-  return CompareTUs(old_tu, new_tu);
+  std::unique_ptr<abi_util::IRDiffDumper> ir_diff_dumper =
+      abi_util::IRDiffDumper::CreateIRDiffDumper("protobuf", cr_);
+  abi_util::CompatibilityStatusIR status =
+      CompareTUs(old_reader.get(), new_reader.get(), ir_diff_dumper.get());
+  if (!ir_diff_dumper->Dump()) {
+    llvm::errs() << "Could not dump diff report\n";
+    ::exit(1);
+  }
+  return status;
 }
 
-CompatibilityStatus HeaderAbiDiff::CompareTUs(
-    const abi_dump::TranslationUnit &old_tu,
-    const abi_dump::TranslationUnit &new_tu) {
-  std::unique_ptr<abi_diff::TranslationUnitDiff> diff_tu(
-      new abi_diff::TranslationUnitDiff);
-  CompatibilityStatus record_status = Collect<abi_dump::RecordDecl>(
-      diff_tu->mutable_records_added(), diff_tu->mutable_records_removed(),
-      diff_tu->mutable_records_diff(), old_tu.records(), new_tu.records(),
-      ignored_symbols_);
+template <typename F>
+static void AddTypesToMap(std::map<std::string, const abi_util::TypeIR *> *dst,
+                          const abi_util::TextFormatToIRReader *tu, F func) {
+  AddToMap(dst, tu->GetRecordTypes(), func);
+  AddToMap(dst, tu->GetEnumTypes(), func);
+  AddToMap(dst, tu->GetPointerTypes(), func);
+  AddToMap(dst, tu->GetBuiltinTypes(), func);
+  AddToMap(dst, tu->GetArrayTypes(), func);
+  AddToMap(dst, tu->GetLvalueReferenceTypes(), func);
+  AddToMap(dst, tu->GetRvalueReferenceTypes(), func);
+  AddToMap(dst, tu->GetQualifiedTypes(), func);
+}
 
-  CompatibilityStatus function_status = Collect<abi_dump::FunctionDecl>(
-      diff_tu->mutable_functions_added(), diff_tu->mutable_functions_removed(),
-      diff_tu->mutable_functions_diff(), old_tu.functions(),
-      new_tu.functions(), ignored_symbols_);
+abi_util::CompatibilityStatusIR HeaderAbiDiff::CompareTUs(
+    const abi_util::TextFormatToIRReader *old_tu,
+    const abi_util::TextFormatToIRReader *new_tu,
+    abi_util::IRDiffDumper *ir_diff_dumper) {
+  // Collect all old and new types in maps, so that we can refer to them by
+  // type name / linker_set_key later.
+  std::map<std::string, const abi_util::TypeIR *> old_types;
+  std::map<std::string, const abi_util::TypeIR *> new_types;
+  AddTypesToMap(&old_types, old_tu,
+                [](const abi_util::TypeIR *e) {return e->GetLinkerSetKey();});
+  AddTypesToMap(&new_types, new_tu,
+                [](const abi_util::TypeIR *e) {return e->GetLinkerSetKey();});
 
-  CompatibilityStatus enum_status = Collect<abi_dump::EnumDecl>(
-      diff_tu->mutable_enums_added(), diff_tu->mutable_enums_removed(),
-      diff_tu->mutable_enums_diff(), old_tu.enums(), new_tu.enums(),
-      ignored_symbols_);
-
-  CompatibilityStatus global_var_status = Collect<abi_dump::GlobalVarDecl>(
-      diff_tu->mutable_global_vars_added(),
-      diff_tu->mutable_global_vars_removed(),
-      diff_tu->mutable_global_vars_diff(), old_tu.global_vars(),
-      new_tu.global_vars(), ignored_symbols_);
-
-  CompatibilityStatus combined_status =
-      record_status | function_status | enum_status | global_var_status;
-
-  if (combined_status & CompatibilityStatus::INCOMPATIBLE) {
-    combined_status = CompatibilityStatus::INCOMPATIBLE;
-  } else if (combined_status & CompatibilityStatus::EXTENSION) {
-    combined_status = CompatibilityStatus::EXTENSION;
-  } else {
-    combined_status = CompatibilityStatus::COMPATIBLE;
-  }
-  diff_tu->set_compatibility_status(combined_status);
-  diff_tu->set_lib_name(lib_name_);
-  diff_tu->set_arch(arch_);
-  std::ofstream text_output(cr_);
-  google::protobuf::io::OstreamOutputStream text_os(&text_output);
-
-  if(!google::protobuf::TextFormat::Print(*diff_tu, &text_os)) {
-    llvm::errs() << "Unable to dump report\n";
+  // Collect fills in added, removed ,unsafe and safe function diffs.
+  if (!CollectDynsymExportables(old_tu->GetFunctions(), new_tu->GetFunctions(),
+                                old_tu->GetElfFunctions(),
+                                new_tu->GetElfFunctions(),
+                                old_types, new_types,
+                                ir_diff_dumper) ||
+      !CollectDynsymExportables(old_tu->GetGlobalVariables(),
+                                new_tu->GetGlobalVariables(),
+                                old_tu->GetElfObjects(),
+                                new_tu->GetElfObjects(),
+                                old_types, new_types,
+                                ir_diff_dumper)) {
+    llvm::errs() << "Unable to collect dynsym exportables\n";
     ::exit(1);
   }
+
+  // By the time this call is reached, all referenced types have been diffed.
+  // So all additional calls on ir_diff_dumper get DiffKind::Unreferenced.
+  if (check_all_apis_ && !CollectUserDefinedTypes(old_tu, new_tu, old_types,
+                                                  new_types, ir_diff_dumper)) {
+    llvm::errs() << "Unable to collect user defined types\n";
+    ::exit(1);
+  }
+
+  abi_util::CompatibilityStatusIR combined_status =
+      ir_diff_dumper->GetCompatibilityStatusIR();
+
+  ir_diff_dumper->AddLibNameIR(lib_name_);
+  ir_diff_dumper->AddArchIR(arch_);
+  ir_diff_dumper->AddCompatibilityStatusIR(combined_status);
   return combined_status;
 }
 
-template <typename T, typename TDiff>
-abi_diff::CompatibilityStatus HeaderAbiDiff::Collect(
-    google::protobuf::RepeatedPtrField<T> *elements_added,
-    google::protobuf::RepeatedPtrField<T> *elements_removed,
-    google::protobuf::RepeatedPtrField<TDiff> *elements_diff,
-    const google::protobuf::RepeatedPtrField<T> &old_srcs,
-    const google::protobuf::RepeatedPtrField<T> &new_srcs,
-    const std::set<std::string> &ignored_symbols) {
-  assert(elements_added != nullptr);
-  assert(elements_removed != nullptr);
-  assert(elements_diff != nullptr);
+bool HeaderAbiDiff::CollectUserDefinedTypes(
+    const abi_util::TextFormatToIRReader *old_tu,
+    const abi_util::TextFormatToIRReader *new_tu,
+    const std::map<std::string, const abi_util::TypeIR *> &old_types_map,
+    const std::map<std::string, const abi_util::TypeIR *> &new_types_map,
+    abi_util::IRDiffDumper *ir_diff_dumper) {
+  return CollectUserDefinedTypesInternal(
+      old_tu->GetRecordTypes(), new_tu->GetRecordTypes(), old_types_map,
+      new_types_map, ir_diff_dumper) &&
+      CollectUserDefinedTypesInternal(old_tu->GetEnumTypes(),
+                                      new_tu->GetEnumTypes(), old_types_map,
+                                      new_types_map, ir_diff_dumper);
+}
 
-  std::map<std::string, const T*> old_elements_map;
-  std::map<std::string, const T*> new_elements_map;
-  AddToMap(&old_elements_map, old_srcs);
-  AddToMap(&new_elements_map, new_srcs);
+template <typename T>
+bool HeaderAbiDiff::CollectUserDefinedTypesInternal(
+    const std::vector<T> &old_ud_types,
+    const std::vector<T> &new_ud_types,
+    const std::map<std::string, const abi_util::TypeIR *> &old_types_map,
+    const std::map<std::string, const abi_util::TypeIR *> &new_types_map,
+    abi_util::IRDiffDumper *ir_diff_dumper) {
+  // No elf information for records and enums.
+  std::map<std::string, const T *> old_ud_types_map;
+  std::map<std::string, const T *> new_ud_types_map;
 
-  if (!PopulateRemovedElements(elements_removed, old_elements_map,
-                               new_elements_map, ignored_symbols) ||
-      !PopulateRemovedElements(elements_added, new_elements_map,
-                               old_elements_map, ignored_symbols) ||
-      !PopulateCommonElements(elements_diff, old_elements_map,
-                              new_elements_map, ignored_symbols)) {
+  abi_util::AddToMap(&old_ud_types_map, old_ud_types,
+                     [](const T *e)
+                     { return e->GetLinkerSetKey();});
+
+  abi_util::AddToMap(&new_ud_types_map, new_ud_types,
+                     [](const T *e)
+                     { return e->GetLinkerSetKey();});
+
+  return Collect(old_ud_types_map, new_ud_types_map, nullptr, nullptr,
+                 ir_diff_dumper) &&
+      PopulateCommonElements(old_ud_types_map, new_ud_types_map, old_types_map,
+                             new_types_map, ir_diff_dumper,
+                             abi_util::IRDiffDumper::Unreferenced);
+}
+
+template <typename T, typename ElfSymbolType>
+bool HeaderAbiDiff::CollectDynsymExportables(
+    const std::vector<T> &old_exportables,
+    const std::vector<T> &new_exportables,
+    const std::vector<ElfSymbolType> &old_elf_symbols,
+    const std::vector<ElfSymbolType> &new_elf_symbols,
+    const std::map<std::string, const abi_util::TypeIR *> &old_types_map,
+    const std::map<std::string, const abi_util::TypeIR *> &new_types_map,
+    abi_util::IRDiffDumper *ir_diff_dumper) {
+  std::map<std::string, const T *> old_exportables_map;
+  std::map<std::string, const T *> new_exportables_map;
+  std::map<std::string, const abi_util::ElfSymbolIR *> old_elf_symbol_map;
+  std::map<std::string, const abi_util::ElfSymbolIR *> new_elf_symbol_map;
+
+  abi_util::AddToMap(&old_exportables_map, old_exportables,
+                     [](const T *e)
+                     { return e->GetLinkerSetKey();});
+  abi_util::AddToMap(&new_exportables_map, new_exportables,
+                     [](const T *e)
+                     { return e->GetLinkerSetKey();});
+  abi_util::AddToMap(
+      &old_elf_symbol_map, old_elf_symbols,
+      [](const ElfSymbolType *symbol) { return symbol->GetName();});
+  abi_util::AddToMap(
+      &new_elf_symbol_map, new_elf_symbols,
+      [](const ElfSymbolType *symbol) { return symbol->GetName();});
+
+  if (!Collect(old_exportables_map,
+               new_exportables_map, &old_elf_symbol_map, &new_elf_symbol_map,
+               ir_diff_dumper) ||
+      !CollectElfSymbols(old_elf_symbol_map, new_elf_symbol_map,
+                         ir_diff_dumper) ||
+      !PopulateCommonElements(old_exportables_map, new_exportables_map,
+                              old_types_map, new_types_map, ir_diff_dumper,
+                              abi_util::IRDiffDumper::Referenced)) {
+    llvm::errs() << "Diffing dynsym exportables failed\n";
+    return false;
+  }
+  return true;
+}
+
+// Collect added and removed Elements. The elf set is needed since some symbols
+// might not have meta-data about them collected through the AST. For eg: if a
+// function Foo is defined in an assembly file on target A, but in a c/c++ file
+// on target B, foo does not have meta-data surrounding it when building target
+// A, this does not mean it is not in the ABI + API of the library.
+
+template <typename T>
+bool HeaderAbiDiff::Collect(
+    const std::map<std::string, const T*> &old_elements_map,
+    const std::map<std::string, const T*> &new_elements_map,
+    const std::map<std::string, const abi_util::ElfSymbolIR *> *old_elf_map,
+    const std::map<std::string, const abi_util::ElfSymbolIR *> *new_elf_map,
+    abi_util::IRDiffDumper *ir_diff_dumper) {
+  if (!PopulateRemovedElements(
+      old_elements_map, new_elements_map, new_elf_map, ir_diff_dumper,
+      abi_util::IRDiffDumper::Removed) ||
+      !PopulateRemovedElements(new_elements_map, old_elements_map, old_elf_map,
+                               ir_diff_dumper,
+                               abi_util::IRDiffDumper::DiffKind::Added)) {
     llvm::errs() << "Populating functions in report failed\n";
-    ::exit(1);
+    return false;
   }
-  if (elements_diff->size() || elements_removed->size()) {
-    return CompatibilityStatus::INCOMPATIBLE;
+  return true;
+}
+
+bool HeaderAbiDiff::CollectElfSymbols(
+    const std::map<std::string, const abi_util::ElfSymbolIR *> &old_symbols,
+    const std::map<std::string, const abi_util::ElfSymbolIR *> &new_symbols,
+    abi_util::IRDiffDumper *ir_diff_dumper) {
+  std::vector<const abi_util::ElfSymbolIR *> removed_elements =
+      abi_util::FindRemovedElements(old_symbols, new_symbols);
+
+  std::vector<const abi_util::ElfSymbolIR *> added_elements =
+      abi_util::FindRemovedElements(new_symbols, old_symbols);
+
+  return PopulateElfElements(removed_elements, ir_diff_dumper,
+                             abi_util::IRDiffDumper::DiffKind::Removed) &&
+         PopulateElfElements(added_elements, ir_diff_dumper,
+                             abi_util::IRDiffDumper::DiffKind::Added);
+}
+
+bool HeaderAbiDiff::PopulateElfElements(
+    std::vector<const abi_util::ElfSymbolIR *> &elf_elements,
+    abi_util::IRDiffDumper *ir_diff_dumper,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  for (auto &&elf_element : elf_elements) {
+    if (!ir_diff_dumper->AddElfSymbolMessageIR(elf_element, diff_kind)) {
+      return false;
+    }
   }
-  if (elements_added->size()) {
-    return CompatibilityStatus::EXTENSION;
-  }
-  return CompatibilityStatus::COMPATIBLE;
+  return true;
 }
 
 template <typename T>
 bool HeaderAbiDiff::PopulateRemovedElements(
-    google::protobuf::RepeatedPtrField<T> *dst,
     const std::map<std::string, const T*> &old_elements_map,
     const std::map<std::string, const T*> &new_elements_map,
-    const std::set<std::string> &ignored_symbols) {
-
-  std::vector<const T *> removed_elements;
-  for (auto &&map_element : old_elements_map) {
-      const T *element = map_element.second;
-      auto new_element =
-          new_elements_map.find(element->basic_abi().linker_set_key());
-      if (new_element == new_elements_map.end()) {
-        removed_elements.emplace_back(element);
-      }
-  }
-  if (!DumpLoneElements(dst, removed_elements, ignored_symbols)) {
+    const std::map<std::string, const abi_util::ElfSymbolIR *> *elf_map,
+    abi_util::IRDiffDumper *ir_diff_dumper,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  std::vector<const T *> removed_elements =
+      abi_util::FindRemovedElements(old_elements_map, new_elements_map);
+  if (!DumpLoneElements(removed_elements, elf_map, ir_diff_dumper, diff_kind)) {
     llvm::errs() << "Dumping added / removed element to report failed\n";
     return false;
   }
   return true;
 }
 
-template <typename T, typename TDiff>
+template <typename T>
 bool HeaderAbiDiff::PopulateCommonElements(
-    google::protobuf::RepeatedPtrField<TDiff> *dst,
     const std::map<std::string, const T *> &old_elements_map,
     const std::map<std::string, const T *> &new_elements_map,
-    const std::set<std::string> &ignored_symbols) {
-  std::vector<std::pair<const T *, const T *>> common_elements;
-  typename std::map<std::string, const T *>::const_iterator old_element =
-      old_elements_map.begin();
-  typename std::map<std::string, const T *>::const_iterator new_element =
-      new_elements_map.begin();
-  while (old_element != old_elements_map.end() &&
-         new_element != new_elements_map.end()) {
-    if (old_element->first == new_element->first) {
-      common_elements.emplace_back(std::make_pair(
-          old_element->second, new_element->second));
-      old_element++;
-      new_element++;
-      continue;
-    }
-    if (old_element->first < new_element->first) {
-      old_element++;
-    } else {
-      new_element++;
-    }
-  }
-  if (!DumpDiffElements(dst, common_elements, ignored_symbols)) {
+    const std::map<std::string, const abi_util::TypeIR *> &old_types,
+    const std::map<std::string, const abi_util::TypeIR *> &new_types,
+    abi_util::IRDiffDumper *ir_diff_dumper,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  std::vector<std::pair<const T *, const T *>> common_elements =
+      abi_util::FindCommonElements(old_elements_map, new_elements_map);
+  if (!DumpDiffElements(common_elements, old_types, new_types,
+                        ir_diff_dumper, diff_kind)) {
     llvm::errs() << "Dumping difference in common element to report failed\n";
     return false;
   }
@@ -185,48 +278,62 @@
 
 template <typename T>
 bool HeaderAbiDiff::DumpLoneElements(
-    google::protobuf::RepeatedPtrField<T> *dst,
     std::vector<const T *> &elements,
-    const std::set<std::string> &ignored_symbols) {
+    const std::map<std::string, const abi_util::ElfSymbolIR *> *elf_map,
+    abi_util::IRDiffDumper *ir_diff_dumper,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  // If the record / enum has source file information, skip it.
+  std::smatch source_file_match;
+  std::regex source_file_regex(" at ");
   for (auto &&element : elements) {
-    if (abi_diff_wrappers::IgnoreSymbol<T>(element, ignored_symbols)) {
+    if (abi_diff_wrappers::IgnoreSymbol<T>(
+        element, ignored_symbols_,
+        [](const T *e) {return e->GetLinkerSetKey();})) {
       continue;
     }
-    T *added_element = dst->Add();
-    if (!added_element) {
-      llvm::errs() << "Adding element diff failed\n";
+    // The element does exist in the .dynsym table, we do not have meta-data
+    // surrounding the element.
+    const std::string &element_linker_set_key = element->GetLinkerSetKey();
+    if ((elf_map != nullptr) &&
+        (elf_map->find(element_linker_set_key) != elf_map->end())) {
+      continue;
+    }
+    if (std::regex_search(element_linker_set_key, source_file_match,
+                          source_file_regex)) {
+      continue;
+    }
+    if (!ir_diff_dumper->AddLinkableMessageIR(element, diff_kind)) {
+      llvm::errs() << "Couldn't dump added /removed element\n";
       return false;
     }
-    *added_element = *element;
   }
   return true;
 }
 
-template <typename T, typename TDiff>
+
+template <typename T>
 bool HeaderAbiDiff::DumpDiffElements(
-    google::protobuf::RepeatedPtrField<TDiff>  *dst,
     std::vector<std::pair<const T *,const T *>> &pairs,
-    const std::set<std::string> &ignored_symbols) {
+    const std::map<std::string, const abi_util::TypeIR *> &old_types,
+    const std::map<std::string, const abi_util::TypeIR *> &new_types,
+    abi_util::IRDiffDumper *ir_diff_dumper,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
   for (auto &&pair : pairs) {
     const T *old_element = pair.first;
     const T *new_element = pair.second;
-    // Not having inheritance from protobuf messages makes this
-    // restrictive code.
-    if (abi_diff_wrappers::IgnoreSymbol<T>(old_element, ignored_symbols)) {
+
+    if (abi_diff_wrappers::IgnoreSymbol<T>(
+        old_element, ignored_symbols_,
+        [](const T *e) {return e->GetLinkerSetKey();})) {
       continue;
     }
-    abi_diff_wrappers::DiffWrapper<T, TDiff> diff_wrapper(old_element,
-                                                          new_element);
-    std::unique_ptr<TDiff> decl_diff_ptr = diff_wrapper.Get();
-    if (!decl_diff_ptr) {
-      continue;
-    }
-    TDiff *added_element_diff = dst->Add();
-    if (!added_element_diff) {
-      llvm::errs() << "Adding element diff failed\n";
+    abi_diff_wrappers::DiffWrapper<T> diff_wrapper(old_element, new_element,
+                                                   ir_diff_dumper, old_types,
+                                                   new_types, &type_cache_);
+    if (!diff_wrapper.DumpDiff(diff_kind)) {
+      llvm::errs() << "Failed to diff elements\n";
       return false;
     }
-    *added_element_diff = *decl_diff_ptr;
   }
   return true;
 }
diff --git a/vndk/tools/header-checker/header-abi-diff/src/abi_diff.h b/vndk/tools/header-checker/header-abi-diff/src/abi_diff.h
index df8a6d1..3cabc8b 100644
--- a/vndk/tools/header-checker/header-abi-diff/src/abi_diff.h
+++ b/vndk/tools/header-checker/header-abi-diff/src/abi_diff.h
@@ -14,6 +14,8 @@
 
 #include "abi_diff_wrappers.h"
 
+#include <ir_representation.h>
+
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunused-parameter"
 #pragma clang diagnostic ignored "-Wnested-anon-types"
@@ -21,68 +23,102 @@
 #include "proto/abi_diff.pb.h"
 #pragma clang diagnostic pop
 
-#include <memory>
-#include <fstream>
-#include <iostream>
 #include <string>
 #include <vector>
 
-
-typedef abi_diff::CompatibilityStatus CompatibilityStatus;
-
 class HeaderAbiDiff {
  public:
   HeaderAbiDiff(const std::string &lib_name, const std::string &arch,
                 const std::string &old_dump, const std::string &new_dump,
                 const std::string &compatibility_report,
-                const std::set<std::string> &ignored_symbols)
+                const std::set<std::string> &ignored_symbols,
+                bool check_all_apis)
       : lib_name_(lib_name), arch_(arch), old_dump_(old_dump),
         new_dump_(new_dump), cr_(compatibility_report),
-      ignored_symbols_(ignored_symbols) { }
+        ignored_symbols_(ignored_symbols), check_all_apis_(check_all_apis) { }
 
-  CompatibilityStatus GenerateCompatibilityReport();
+  abi_util::CompatibilityStatusIR GenerateCompatibilityReport();
 
  private:
-  CompatibilityStatus CompareTUs(const abi_dump::TranslationUnit &old_tu,
-                                 const abi_dump::TranslationUnit &new_tu);
-  // Collect* methods fill in the diff_tu.
-  template <typename T, typename TDiff>
-  static CompatibilityStatus Collect(
-      google::protobuf::RepeatedPtrField<T> *elements_added,
-      google::protobuf::RepeatedPtrField<T> *elements_removed,
-      google::protobuf::RepeatedPtrField<TDiff> *elements_diff,
-      const google::protobuf::RepeatedPtrField<T> &old_srcs,
-      const google::protobuf::RepeatedPtrField<T> &new_srcs,
-      const std::set<std::string> &ignored_symbols);
+  abi_util::CompatibilityStatusIR CompareTUs(
+      const abi_util::TextFormatToIRReader *old_tu,
+      const abi_util::TextFormatToIRReader *new_tu,
+      abi_util::IRDiffDumper *ir_diff_dumper);
+
+  template <typename T, typename ElfSymbolType>
+  bool CollectDynsymExportables(
+    const std::vector<T> &old_exportables,
+    const std::vector<T> &new_exportables,
+    const std::vector<ElfSymbolType> &old_elf_symbols,
+    const std::vector<ElfSymbolType> &new_elf_symbols,
+    const std::map<std::string, const abi_util::TypeIR *> &old_types_map,
+    const std::map<std::string, const abi_util::TypeIR *> &new_types_map,
+    abi_util::IRDiffDumper *ir_diff_dumper);
 
   template <typename T>
-  static inline void AddToMap(std::map<std::string, const T *> *dst,
-                              const google::protobuf::RepeatedPtrField<T> &src);
+  bool Collect(
+      const std::map<std::string, const T *> &old_elements_map,
+      const std::map<std::string, const T *> &new_elements_map,
+      const std::map<std::string, const abi_util::ElfSymbolIR *> *old_elf_map,
+      const std::map<std::string, const abi_util::ElfSymbolIR *> *new_elf_map,
+      abi_util::IRDiffDumper *ir_diff_dumper);
+
+  bool CollectElfSymbols(
+      const std::map<std::string, const abi_util::ElfSymbolIR *> &old_symbols,
+      const std::map<std::string, const abi_util::ElfSymbolIR *> &new_symbols,
+      abi_util::IRDiffDumper *ir_diff_dumper);
+
+  bool PopulateElfElements(
+      std::vector<const abi_util::ElfSymbolIR *> &elf_elements,
+      abi_util::IRDiffDumper *ir_diff_dumper,
+      abi_util::IRDiffDumper::DiffKind diff_kind);
 
   template <typename T>
-  static bool PopulateRemovedElements(
-      google::protobuf::RepeatedPtrField<T> *dst,
+  bool PopulateRemovedElements(
       const std::map<std::string, const T *> &old_elements_map,
       const std::map<std::string, const T *> &new_elements_map,
-      const std::set<std::string> &ignored_symbols);
+      const std::map<std::string, const abi_util::ElfSymbolIR *> *elf_map,
+      abi_util::IRDiffDumper *ir_diff_dumper,
+      abi_util::IRDiffDumper::DiffKind diff_kind);
 
-  template <typename T, typename TDiff>
-  static bool PopulateCommonElements(
-      google::protobuf::RepeatedPtrField<TDiff> *dst,
+  template <typename T>
+  bool PopulateCommonElements(
       const std::map<std::string, const T *> &old_elements_map,
       const std::map<std::string, const T *> &new_elements_map,
-      const std::set<std::string> &ignored_symbols);
+      const std::map<std::string, const abi_util::TypeIR *> &old_types,
+      const std::map<std::string, const abi_util::TypeIR *> &new_types,
+      abi_util::IRDiffDumper *ir_diff_dumper,
+      abi_util::IRDiffDumper::DiffKind diff_kind);
 
-  template <typename T, typename TDiff>
-  static bool DumpDiffElements(
-      google::protobuf::RepeatedPtrField<TDiff> *dst,
+  template <typename T>
+  bool DumpDiffElements(
       std::vector<std::pair<const T *, const T *>> &pairs,
-      const std::set<std::string> &ignored_symbols);
+      const std::map<std::string, const abi_util::TypeIR *> &old_types,
+      const std::map<std::string, const abi_util::TypeIR *> &new_types,
+      abi_util::IRDiffDumper *ir_diff_dumper,
+      abi_util::IRDiffDumper::DiffKind diff_kind);
 
   template <typename T>
-  static bool DumpLoneElements(google::protobuf::RepeatedPtrField<T> *dst,
-                               std::vector<const T *> &elements,
-                               const std::set<std::string> &ignored_symbols);
+  bool DumpLoneElements(
+      std::vector<const T *> &elements,
+      const std::map<std::string, const abi_util::ElfSymbolIR *> *elf_map,
+      abi_util::IRDiffDumper *ir_diff_dumper,
+      abi_util::IRDiffDumper::DiffKind diff_kind);
+
+  bool CollectUserDefinedTypes(
+      const abi_util::TextFormatToIRReader *old_tu,
+      const abi_util::TextFormatToIRReader *new_tu,
+      const std::map<std::string, const abi_util::TypeIR *> &old_types_map,
+      const std::map<std::string, const abi_util::TypeIR *> &new_types_map,
+      abi_util::IRDiffDumper *ir_diff_dumper);
+
+  template <typename T>
+  bool CollectUserDefinedTypesInternal(
+      const std::vector<T> &old_ud_types,
+      const std::vector<T> &new_ud_types,
+      const std::map<std::string, const abi_util::TypeIR *> &old_types_map,
+      const std::map<std::string, const abi_util::TypeIR *> &new_types_map,
+      abi_util::IRDiffDumper *ir_diff_dumper);
 
  private:
   const std::string &lib_name_;
@@ -91,27 +127,6 @@
   const std::string &new_dump_;
   const std::string &cr_;
   const std::set<std::string> &ignored_symbols_;
+  bool check_all_apis_;
+  std::set<std::string> type_cache_;
 };
-
-template <typename T>
-inline void HeaderAbiDiff::AddToMap(
-    std::map<std::string, const T *> *dst,
-    const google::protobuf::RepeatedPtrField<T> &src) {
-  for (auto &&element : src) {
-    dst->insert(std::make_pair(element.basic_abi().linker_set_key(), &element));
-  }
-}
-
-static inline CompatibilityStatus operator|(CompatibilityStatus f,
-                                            CompatibilityStatus s) {
-  return static_cast<CompatibilityStatus>(
-      static_cast<std::underlying_type<CompatibilityStatus>::type>(f) |
-      static_cast<std::underlying_type<CompatibilityStatus>::type>(s));
-}
-
-static inline CompatibilityStatus operator&(
-    CompatibilityStatus f, CompatibilityStatus s) {
-  return static_cast<CompatibilityStatus>(
-      static_cast<std::underlying_type<CompatibilityStatus>::type>(f) &
-      static_cast<std::underlying_type<CompatibilityStatus>::type>(s));
-}
diff --git a/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.cpp b/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.cpp
index e75d4ce..e9a0047 100644
--- a/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.cpp
+++ b/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.cpp
@@ -14,52 +14,23 @@
 
 #include "abi_diff_wrappers.h"
 
-#include<header_abi_util.h>
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-parameter"
-#pragma clang diagnostic ignored "-Wnested-anon-types"
-#include "proto/abi_dump.pb.h"
-#include "proto/abi_diff.pb.h"
-#pragma clang diagnostic pop
+#include <header_abi_util.h>
 
 #include <llvm/Support/raw_ostream.h>
 
-using abi_diff::RecordDeclDiff;
-using abi_diff::RecordFieldDeclDiff;
-using abi_diff::CXXBaseSpecifierDiff;
-using abi_diff::CXXVTableDiff;
-using abi_diff::EnumDeclDiff;
-using abi_diff::ReturnTypeDiff;
-using abi_diff::ParamDeclDiff;
-using abi_diff::FunctionDeclDiff;
-using abi_diff::EnumDeclDiff;
-using abi_diff::EnumFieldDeclDiff;
-using abi_diff::GlobalVarDeclDiff;
-using abi_dump::RecordDecl;
-using abi_dump::RecordFieldDecl;
-using abi_dump::EnumDecl;
-using abi_dump::EnumFieldDecl;
-using abi_dump::FunctionDecl;
-using abi_dump::ParamDecl;
-using abi_dump::VTableComponent;
-using abi_dump::CXXBaseSpecifier;
-using abi_dump::GlobalVarDecl;
-using abi_dump::BasicNamedAndTypedDecl;
-
 namespace abi_diff_wrappers {
 
-static bool IsAccessDownGraded(abi_dump::AccessSpecifier old_access,
-                               abi_dump::AccessSpecifier new_access) {
+static bool IsAccessDownGraded(abi_util::AccessSpecifierIR old_access,
+                               abi_util::AccessSpecifierIR new_access) {
   bool access_downgraded = false;
   switch (old_access) {
-    case abi_dump::AccessSpecifier::protected_access:
-      if (new_access == abi_dump::AccessSpecifier::private_access) {
+    case abi_util::AccessSpecifierIR::ProtectedAccess:
+      if (new_access == abi_util::AccessSpecifierIR::PrivateAccess) {
         access_downgraded = true;
       }
       break;
-    case abi_dump::AccessSpecifier::public_access:
-      if (new_access != abi_dump::AccessSpecifier::public_access) {
+    case abi_util::AccessSpecifierIR::PublicAccess:
+      if (new_access != abi_util::AccessSpecifierIR::PublicAccess) {
         access_downgraded = true;
       }
       break;
@@ -69,255 +40,590 @@
   return access_downgraded;
 }
 
-static std::string CpptoCAdjustment(const std::string &type) {
-  std::string adjusted_type_name =
-      abi_util::FindAndReplace(type, "\\bstruct ", "");
-
-  return adjusted_type_name;
+static std::string Unwind(const std::deque<std::string> *type_queue) {
+  if (!type_queue) {
+    return "";
+  }
+  std::string stack_str;
+  std::deque<std::string> type_queue_copy = *type_queue;
+  while (!type_queue_copy.empty()) {
+    stack_str += type_queue_copy.front() + "-> ";
+    type_queue_copy.pop_front();
+  }
+  return stack_str;
 }
 
-static bool CompareTypeNames(const abi_dump::BasicTypeAbi &old_abi,
-                             const abi_dump::BasicTypeAbi &new_abi) {
-  // Strip of leading 'struct' keyword from type names
-  std::string old_type = old_abi.name();
-  std::string new_type = new_abi.name();
-  old_type = CpptoCAdjustment(old_type);
-  new_type = CpptoCAdjustment(new_type);
-  // TODO: Add checks for C++ built-in types vs C corresponding types.
-  return old_type != new_type;
+void DiffWrapperBase::CompareEnumFields(
+    const std::vector<abi_util::EnumFieldIR> &old_fields,
+    const std::vector<abi_util::EnumFieldIR> &new_fields,
+    abi_util::EnumTypeDiffIR *enum_type_diff_ir) {
+  std::map<std::string, const abi_util::EnumFieldIR *> old_fields_map;
+  std::map<std::string, const abi_util::EnumFieldIR *> new_fields_map;
+  abi_util::AddToMap(&old_fields_map, old_fields,
+                     [](const abi_util::EnumFieldIR *f)
+                     {return f->GetName();});
+  abi_util::AddToMap(&new_fields_map, new_fields,
+                     [](const abi_util::EnumFieldIR *f)
+                     {return f->GetName();});
+  std::vector<const abi_util::EnumFieldIR *> removed_fields =
+      abi_util::FindRemovedElements(old_fields_map, new_fields_map);
+
+  std::vector<const abi_util::EnumFieldIR *> added_fields =
+      abi_util::FindRemovedElements(new_fields_map, old_fields_map);
+
+  enum_type_diff_ir->SetFieldsAdded(std::move(added_fields));
+
+  enum_type_diff_ir->SetFieldsRemoved(std::move(removed_fields));
+
+  std::vector<std::pair<
+      const abi_util::EnumFieldIR *, const abi_util::EnumFieldIR *>> cf =
+      abi_util::FindCommonElements(old_fields_map, new_fields_map);
+  std::vector<abi_util::EnumFieldDiffIR> enum_field_diffs;
+  for (auto &&common_fields : cf) {
+    if (common_fields.first->GetValue() != common_fields.second->GetValue()) {
+      abi_util::EnumFieldDiffIR enum_field_diff_ir(common_fields.first,
+                                                   common_fields.second);
+      enum_field_diffs.emplace_back(std::move(enum_field_diff_ir));
+    }
+  }
+  enum_type_diff_ir->SetFieldsDiff(std::move(enum_field_diffs));
 }
 
-static bool DiffBasicTypeAbi(const abi_dump::BasicTypeAbi &old_abi,
-                             const abi_dump::BasicTypeAbi &new_abi) {
-  // We need to add a layer of indirection to account for issues when C and C++
-  // are mixed. For example some types like wchar_t are in-built types for C++
-  // but not for C. Another example would be clang reporting C structures
-  // without the leading "struct" keyword when headers defining them are
-  // included in C++ files.
-  bool name_comparison = CompareTypeNames(old_abi, new_abi);
-  bool size_comparison = (old_abi.size() != new_abi.size());
-  bool alignment_comparison = (old_abi.alignment() != new_abi.alignment());
-  return name_comparison || size_comparison || alignment_comparison;
+DiffStatus DiffWrapperBase::CompareEnumTypes(
+    const abi_util::EnumTypeIR *old_type, const abi_util::EnumTypeIR *new_type,
+     std::deque<std::string> *type_queue,
+     abi_util::IRDiffDumper::DiffKind diff_kind) {
+  if (old_type->GetName() != new_type->GetName()) {
+    return DiffStatus::direct_diff;
+  }
+  auto enum_type_diff_ir = std::make_unique<abi_util::EnumTypeDiffIR>();
+  enum_type_diff_ir->SetName(old_type->GetName());
+  const std::string &old_underlying_type = old_type->GetUnderlyingType();
+  const std::string &new_underlying_type = new_type->GetUnderlyingType();
+  if (old_underlying_type != new_underlying_type) {
+    enum_type_diff_ir->SetUnderlyingTypeDiff(
+        std::make_unique<std::pair<std::string, std::string>>(
+            old_underlying_type, new_underlying_type));
+  }
+  CompareEnumFields(old_type->GetFields(), new_type->GetFields(),
+                    enum_type_diff_ir.get());
+  if ((enum_type_diff_ir->IsExtended() ||
+       enum_type_diff_ir->IsIncompatible()) &&
+      !ir_diff_dumper_->AddDiffMessageIR(enum_type_diff_ir.get(),
+                                         Unwind(type_queue), diff_kind)) {
+    llvm::errs() << "AddDiffMessage on EnumTypeDiffIR failed\n";
+    ::exit(1);
+  }
+  return DiffStatus::no_diff;
 }
 
-template <typename T>
-static bool Diff(const T &old_element, const T &new_element) {
-  // Can be specialized for future changes in the format.
-  return DiffBasicTypeAbi(old_element.basic_abi().type_abi(),
-                          new_element.basic_abi().type_abi()) ||
-      (old_element.basic_abi().name() != new_element.basic_abi().name()) ||
-      IsAccessDownGraded(old_element.basic_abi().access(),
-                         new_element.basic_abi().access());
+bool DiffWrapperBase::CompareVTableComponents(
+    const abi_util::VTableComponentIR &old_component,
+    const abi_util::VTableComponentIR &new_component) {
+  return old_component.GetName() == new_component.GetName() &&
+      old_component.GetValue() == new_component.GetValue() &&
+      old_component.GetKind() == new_component.GetKind();
 }
 
-template <>
-bool Diff<EnumFieldDecl>(const EnumFieldDecl &old_element,
-                         const EnumFieldDecl &new_element) {
-  // Can be specialized for future changes in the format.
-  return DiffBasicTypeAbi(old_element.basic_abi().type_abi(),
-                          new_element.basic_abi().type_abi()) ||
-      (old_element.enum_field_value() != new_element.enum_field_value()) ||
-      (old_element.basic_abi().name() != new_element.basic_abi().name());
+bool DiffWrapperBase::CompareVTables(
+    const abi_util::RecordTypeIR *old_record,
+    const abi_util::RecordTypeIR *new_record) {
+
+  const std::vector<abi_util::VTableComponentIR> &old_components =
+      old_record->GetVTableLayout().GetVTableComponents();
+  const std::vector<abi_util::VTableComponentIR> &new_components =
+      new_record->GetVTableLayout().GetVTableComponents();
+  if (old_components.size() > new_components.size()) {
+    // Something in the vtable got deleted.
+    return false;
+  }
+  uint32_t i = 0;
+  while (i < old_components.size()) {
+    auto &old_element = old_components.at(i);
+    auto &new_element = new_components.at(i);
+    if (!CompareVTableComponents(old_element, new_element)) {
+      return false;
+    }
+    i++;
+  }
+  return true;
 }
 
-template <>
-bool Diff<ParamDecl>(const ParamDecl &old_element,
-                     const ParamDecl &new_element) {
-  // Can be specialized for future changes in the format.
-  return DiffBasicTypeAbi(old_element.basic_abi().type_abi(),
-                          new_element.basic_abi().type_abi());
+bool DiffWrapperBase::CompareSizeAndAlignment(
+    const abi_util::TypeIR *old_type,
+    const abi_util::TypeIR *new_type) {
+  return old_type->GetSize() == new_type->GetSize() &&
+      old_type->GetAlignment() == new_type->GetAlignment();
 }
 
-template <>
-bool Diff<CXXBaseSpecifier>(const CXXBaseSpecifier &old_element,
-                            const CXXBaseSpecifier &new_element) {
-  // Can be specialized for future changes in the format.
-  return (DiffBasicTypeAbi(old_element.basic_abi().type_abi(),
-                           new_element.basic_abi().type_abi()) ||
-      old_element.basic_abi().access() != new_element.basic_abi().access() ||
-      old_element.is_virtual() != new_element.is_virtual());
+std::unique_ptr<abi_util::RecordFieldDiffIR>
+DiffWrapperBase::CompareCommonRecordFields(
+    const abi_util::RecordFieldIR *old_field,
+    const abi_util::RecordFieldIR *new_field,
+    std::deque<std::string> *type_queue,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  if (old_field->GetOffset() != new_field->GetOffset() ||
+      // TODO: Should this be an inquality check instead ? Some compilers can
+      // make signatures dependant on absolute values of access specifiers.
+      IsAccessDownGraded(old_field->GetAccess(), new_field->GetAccess()) ||
+      CompareAndDumpTypeDiff(old_field->GetReferencedType(),
+                             new_field->GetReferencedType(),
+                             type_queue, diff_kind) ==
+      DiffStatus::direct_diff) {
+    return std::make_unique<abi_util::RecordFieldDiffIR>(old_field, new_field);
+  }
+  return nullptr;
 }
 
-template <>
-bool Diff<VTableComponent>(const VTableComponent &old_element,
-                           const VTableComponent &new_element) {
-  bool kind_comparison = old_element.kind() != new_element.kind();
-  bool mangled_name_comparison = old_element.mangled_component_name() !=
-      new_element.mangled_component_name();
-  bool value_comparison =
-      old_element.component_value() != new_element.component_value();
-  return kind_comparison || mangled_name_comparison || value_comparison;
+std::pair<std::vector<abi_util::RecordFieldDiffIR>,
+    std::vector<const abi_util::RecordFieldIR *>>
+DiffWrapperBase::CompareRecordFields(
+    const std::vector<abi_util::RecordFieldIR> &old_fields,
+    const std::vector<abi_util::RecordFieldIR> &new_fields,
+    std::deque<std::string> *type_queue,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  std::pair<std::vector<abi_util::RecordFieldDiffIR>,
+  std::vector<const abi_util::RecordFieldIR *>> diffed_and_removed_fields;
+  std::map<std::string, const abi_util::RecordFieldIR *> old_fields_map;
+  std::map<std::string, const abi_util::RecordFieldIR *> new_fields_map;
+  std::map<uint64_t, const abi_util::RecordFieldIR *> old_fields_offset_map;
+  std::map<uint64_t, const abi_util::RecordFieldIR *> new_fields_offset_map;
+
+  abi_util::AddToMap(&old_fields_map, old_fields,
+                     [](const abi_util::RecordFieldIR *f)
+                     {return f->GetName();});
+  abi_util::AddToMap(&new_fields_map, new_fields,
+                     [](const abi_util::RecordFieldIR *f)
+                     {return f->GetName();});
+  abi_util::AddToMap(&old_fields_offset_map, old_fields,
+                     [](const abi_util::RecordFieldIR *f)
+                     {return f->GetOffset();});
+  abi_util::AddToMap(&new_fields_offset_map, new_fields,
+                     [](const abi_util::RecordFieldIR *f)
+                     {return f->GetOffset();});
+  // If a field is removed from the map field_name -> offset see if another
+  // field is present at the same offset and compare the size and type etc,
+  // remove it from the removed fields if they're compatible.
+  std::vector<const abi_util::RecordFieldIR *> removed_fields =
+      abi_util::FindRemovedElements(old_fields_map, new_fields_map);
+  uint32_t i = 0;
+  for (auto &&removed_field : removed_fields) {
+    // For the removed field, get the corresponding offset from the old map.
+    // Compare the fields from old map and new map if there's a direct diff,
+    // continue, otherwise remove that field from the removed fields map.
+    uint64_t old_field_offset = removed_field->GetOffset();
+    auto corresponding_field_at_same_offset =
+        new_fields_offset_map.find(old_field_offset);
+    // Correctly reported as removed.
+    if (corresponding_field_at_same_offset == new_fields_offset_map.end()) {
+      continue;
+    }
+    auto comparison_result = CompareCommonRecordFields(
+        removed_field, corresponding_field_at_same_offset->second,
+        type_queue, diff_kind);
+    if (comparison_result != nullptr) {
+      continue;
+    }
+    removed_fields.erase(removed_fields.begin() + i);
+    i++;
+  }
+  diffed_and_removed_fields.second = std::move(removed_fields);
+  std::vector<std::pair<
+      const abi_util::RecordFieldIR *, const abi_util::RecordFieldIR *>> cf =
+      abi_util::FindCommonElements(old_fields_map, new_fields_map);
+  for (auto &&common_fields : cf) {
+    std::unique_ptr<abi_util::RecordFieldDiffIR> diffed_field_ptr =
+        CompareCommonRecordFields(common_fields.first, common_fields.second,
+                                  type_queue, diff_kind);
+    if (diffed_field_ptr != nullptr) {
+      diffed_and_removed_fields.first.emplace_back(
+          std::move(*(diffed_field_ptr.release())));
+    }
+  }
+  return diffed_and_removed_fields;
 }
 
-// This function fills in a *Diff Message's repeated field. For eg:
-// RecordDeclDiff's CXXBaseSpecifierDiff fields and well as FieldDeclDiff
-// fields.
-template <typename T, typename TDiff>
-template <typename Element, typename ElementDiff>
-bool DiffWrapperBase<T, TDiff>::GetElementDiffs(
-    google::protobuf::RepeatedPtrField<ElementDiff> *dst,
-    const google::protobuf::RepeatedPtrField<Element> &old_elements,
-    const google::protobuf::RepeatedPtrField<Element> &new_elements) {
-  bool differs = false;
-  assert(dst != nullptr);
+bool DiffWrapperBase::CompareBaseSpecifiers(
+    const std::vector<abi_util::CXXBaseSpecifierIR> &old_base_specifiers,
+    const std::vector<abi_util::CXXBaseSpecifierIR> &new_base_specifiers,
+    std::deque<std::string> *type_queue,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  if (old_base_specifiers.size() != new_base_specifiers.size()) {
+    return false;
+  }
   int i = 0;
-  int j = 0;
-  while (i < old_elements.size() && j < new_elements.size()) {
-    const Element &old_element = old_elements.Get(i);
-    const Element &new_element = new_elements.Get(i);
-
-    if (Diff(old_element, new_element)) {
-      ElementDiff *diff = dst->Add();
-      Element *old_elementp = nullptr;
-      Element *new_elementp = nullptr;
-      if (!diff || !(old_elementp = diff->mutable_old()) ||
-          !(new_elementp = diff->mutable_new_())) {
-        llvm::errs() << "Failed to add diff element\n";
-        ::exit(1);
-      }
-      *old_elementp = old_element;
-      *new_elementp = new_element;
-      diff->set_index(i);
-      differs = true;
+  while (i < old_base_specifiers.size()) {
+    if (CompareAndDumpTypeDiff(old_base_specifiers.at(i).GetReferencedType(),
+                               new_base_specifiers.at(i).GetReferencedType(),
+                               type_queue, diff_kind) ==
+        DiffStatus::direct_diff ||
+        (old_base_specifiers.at(i).GetAccess() !=
+         new_base_specifiers.at(i).GetAccess())) {
+      return false;
     }
     i++;
-    j++;
   }
-  if (old_elements.size() != new_elements.size()) {
-    GetExtraElementDiffs(dst, i, j, old_elements, new_elements);
-    differs = true;
-  }
-  return differs;
+  return true;
 }
 
-template <typename T, typename TDiff>
-template <typename Element, typename ElementDiff>
-void DiffWrapperBase<T, TDiff>::GetExtraElementDiffs(
-    google::protobuf::RepeatedPtrField<ElementDiff> *dst, int i, int j,
-    const google::protobuf::RepeatedPtrField<Element> &old_elements,
-    const google::protobuf::RepeatedPtrField<Element> &new_elements) {
- assert(dst != nullptr);
- while (i < old_elements.size()) {
-    const Element &old_element = old_elements.Get(i);
-    ElementDiff *diff = dst->Add();
-    Element *old_elementp = nullptr;
-    if (!diff || !(old_elementp = diff->mutable_old())) {
-      llvm::errs() << "Failed to add diff element\n";
-      ::exit(1);
-    }
-    *old_elementp = old_element;
-    diff->set_index(i);
+void DiffWrapperBase::CompareTemplateInfo(
+    const std::vector<abi_util::TemplateElementIR> &old_template_elements,
+    const std::vector<abi_util::TemplateElementIR> &new_template_elements,
+    std::deque<std::string> *type_queue,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  uint32_t old_template_size = old_template_elements.size();
+  assert(old_template_size == new_template_elements.size());
+  uint32_t i = 0;
+  while (i < old_template_size) {
+    const abi_util::TemplateElementIR &old_template_element =
+        old_template_elements[i];
+    const abi_util::TemplateElementIR &new_template_element =
+        new_template_elements[i];
+    CompareAndDumpTypeDiff(old_template_element.GetReferencedType(),
+                           new_template_element.GetReferencedType(),
+                           type_queue, diff_kind);
     i++;
- }
- while (j < new_elements.size()) {
-    const Element &new_element = new_elements.Get(j);
-    ElementDiff *diff = dst->Add();
-    Element *new_elementp = nullptr;
-    if (!diff || !(new_elementp = diff->mutable_new_())) {
-      llvm::errs() << "Failed to add diff element\n";
-      ::exit(1);
-    }
-    *new_elementp = new_element;
-    diff->set_index(j);
-    j++;
- }
+  }
 }
 
-static bool DiffBasicNamedAndTypedDecl(BasicNamedAndTypedDecl *type_diff_old,
-                                       BasicNamedAndTypedDecl *type_diff_new,
-                                       const BasicNamedAndTypedDecl &old,
-                                       const BasicNamedAndTypedDecl &new_) {
-  assert(type_diff_old != nullptr);
-  assert(type_diff_new != nullptr);
-  if (DiffBasicTypeAbi(old.type_abi(), new_.type_abi()) ||
-      IsAccessDownGraded(old.access(), new_.access())) {
-    *(type_diff_old) = old;
-    *(type_diff_new) = new_;
+DiffStatus DiffWrapperBase::CompareRecordTypes(
+    const abi_util::RecordTypeIR *old_type,
+    const abi_util::RecordTypeIR *new_type,
+    std::deque<std::string> *type_queue,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  auto record_type_diff_ir = std::make_unique<abi_util::RecordTypeDiffIR>();
+  // Compare names.
+  if (old_type->GetName() != new_type->GetName()) {
+    // Do not dump anything since the record types themselves are fundamentally
+    // different.
+    return DiffStatus::direct_diff;
+  }
+  record_type_diff_ir->SetName(old_type->GetName());
+  if (old_type->GetAccess() != new_type->GetAccess()) {
+    record_type_diff_ir->SetAccessDiff(
+        std::make_unique<abi_util::AccessSpecifierDiffIR>(
+            old_type->GetAccess(), new_type->GetAccess()));
+  }
+
+  if (!CompareSizeAndAlignment(old_type, new_type)) {
+    record_type_diff_ir->SetTypeDiff(
+        std::make_unique<abi_util::TypeDiffIR>(
+            std::make_pair(old_type->GetSize(), new_type->GetSize()),
+            std::make_pair(old_type->GetAlignment(),
+                           new_type->GetAlignment())));
+  }
+  if (!CompareVTables(old_type, new_type)) {
+    record_type_diff_ir->SetVTableLayoutDiff(
+        std::make_unique<abi_util::VTableLayoutDiffIR>(
+            old_type->GetVTableLayout(), new_type->GetVTableLayout()));
+  }
+  std::pair<std::vector<abi_util::RecordFieldDiffIR>,
+      std::vector<const abi_util::RecordFieldIR *>> field_diffs;
+  field_diffs = CompareRecordFields(old_type->GetFields(),
+                                    new_type->GetFields(), type_queue,
+                                    diff_kind);
+  record_type_diff_ir->SetFieldDiffs(std::move(field_diffs.first));
+  record_type_diff_ir->SetFieldsRemoved(std::move(field_diffs.second));
+  const std::vector<abi_util::CXXBaseSpecifierIR> &old_bases =
+      old_type->GetBases();
+  const std::vector<abi_util::CXXBaseSpecifierIR> &new_bases =
+      new_type->GetBases();
+
+  if (!CompareBaseSpecifiers(old_bases, new_bases, type_queue, diff_kind)) {
+    record_type_diff_ir->SetBaseSpecifierDiffs(
+        std::make_unique<abi_util::CXXBaseSpecifierDiffIR>(old_bases,
+                                                           new_bases));
+  }
+  if (record_type_diff_ir->DiffExists() &&
+      !ir_diff_dumper_->AddDiffMessageIR(record_type_diff_ir.get(),
+                                         Unwind(type_queue), diff_kind)) {
+    llvm::errs() << "AddDiffMessage on record type failed\n";
+    ::exit(1);
+  } // No need to add a dump for an extension since records can't be "extended".
+
+  CompareTemplateInfo(old_type->GetTemplateElements(),
+                      new_type->GetTemplateElements(),
+                      type_queue, diff_kind);
+
+  return DiffStatus::no_diff;
+}
+
+DiffStatus DiffWrapperBase::CompareLvalueReferenceTypes(
+    const abi_util::LvalueReferenceTypeIR *old_type,
+    const abi_util::LvalueReferenceTypeIR *new_type,
+    std::deque<std::string> *type_queue,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
+                                new_type->GetReferencedType(),
+                                type_queue, diff_kind);
+}
+
+DiffStatus DiffWrapperBase::CompareRvalueReferenceTypes(
+    const abi_util::RvalueReferenceTypeIR *old_type,
+    const abi_util::RvalueReferenceTypeIR *new_type,
+    std::deque<std::string> *type_queue,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
+                                new_type->GetReferencedType(),
+                                type_queue, diff_kind);
+}
+
+DiffStatus DiffWrapperBase::CompareQualifiedTypes(
+    const abi_util::QualifiedTypeIR *old_type,
+    const abi_util::QualifiedTypeIR *new_type,
+    std::deque<std::string> *type_queue,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  // If all the qualifiers are not the same, return direct_diff, else
+  // recursively compare the unqualified types.
+  if (old_type->IsConst() != new_type->IsConst() ||
+      old_type->IsVolatile() != new_type->IsVolatile() ||
+      old_type->IsRestricted() != new_type->IsRestricted()) {
+    return DiffStatus::direct_diff;
+  }
+  return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
+                                new_type->GetReferencedType(),
+                                type_queue, diff_kind);
+}
+
+DiffStatus DiffWrapperBase::ComparePointerTypes(
+    const abi_util::PointerTypeIR *old_type,
+    const abi_util::PointerTypeIR *new_type,
+    std::deque<std::string> *type_queue,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  // The following need to be the same for two pointer types to be considered
+  // equivalent:
+  // 1) Number of pointer indirections are the same.
+  // 2) The ultimate pointee is the same.
+  assert(CompareSizeAndAlignment(old_type, new_type));
+  return CompareAndDumpTypeDiff(old_type->GetReferencedType(),
+                                new_type->GetReferencedType(),
+                                type_queue, diff_kind);
+}
+
+DiffStatus DiffWrapperBase::CompareBuiltinTypes(
+    const abi_util::BuiltinTypeIR *old_type,
+    const abi_util::BuiltinTypeIR *new_type) {
+  // If the size, alignment and is_unsigned are the same, return no_diff
+  // else return direct_diff.
+  uint64_t old_signedness = old_type->IsUnsigned();
+  uint64_t new_signedness = new_type->IsUnsigned();
+
+  if (!CompareSizeAndAlignment(old_type, new_type) ||
+      old_signedness != new_signedness ||
+      old_type->IsIntegralType() != new_type->IsIntegralType()) {
+    return DiffStatus::direct_diff;
+  }
+  return DiffStatus::no_diff;
+}
+
+DiffStatus DiffWrapperBase::CompareFunctionParameters(
+    const std::vector<abi_util::ParamIR> &old_parameters,
+    const std::vector<abi_util::ParamIR> &new_parameters,
+    std::deque<std::string> *type_queue,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  size_t old_parameters_size = old_parameters.size();
+  if (old_parameters_size != new_parameters.size()) {
+    return DiffStatus::direct_diff;
+  }
+  uint64_t i = 0;
+  while (i < old_parameters_size) {
+    const abi_util::ParamIR &old_parameter = old_parameters.at(i);
+    const abi_util::ParamIR &new_parameter = new_parameters.at(i);
+    if ((CompareAndDumpTypeDiff(old_parameter.GetReferencedType(),
+                               new_parameter.GetReferencedType(),
+                               type_queue, diff_kind) ==
+        DiffStatus::direct_diff) ||
+        (old_parameter.GetIsDefault() != new_parameter.GetIsDefault())) {
+      return DiffStatus::direct_diff;
+    }
+    i++;
+  }
+  return DiffStatus::no_diff;
+}
+
+DiffStatus DiffWrapperBase::CompareAndDumpTypeDiff(
+    const abi_util::TypeIR *old_type, const abi_util::TypeIR *new_type,
+    abi_util::LinkableMessageKind kind, std::deque<std::string> *type_queue,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  if (kind == abi_util::LinkableMessageKind::BuiltinTypeKind) {
+    return CompareBuiltinTypes(
+        static_cast<const abi_util::BuiltinTypeIR *>(old_type),
+        static_cast<const abi_util::BuiltinTypeIR *>(new_type));
+  }
+
+  if (kind == abi_util::LinkableMessageKind::QualifiedTypeKind) {
+    return CompareQualifiedTypes(
+        static_cast<const abi_util::QualifiedTypeIR *>(old_type),
+        static_cast<const abi_util::QualifiedTypeIR *>(new_type),
+        type_queue, diff_kind);
+  }
+
+  if (kind == abi_util::LinkableMessageKind::EnumTypeKind) {
+      return CompareEnumTypes(
+          static_cast<const abi_util::EnumTypeIR *>(old_type),
+          static_cast<const abi_util::EnumTypeIR *>(new_type),
+          type_queue, diff_kind);
+
+  }
+
+  if (kind == abi_util::LinkableMessageKind::LvalueReferenceTypeKind) {
+    return CompareLvalueReferenceTypes(
+        static_cast<const abi_util::LvalueReferenceTypeIR *>(old_type),
+        static_cast<const abi_util::LvalueReferenceTypeIR *>(new_type),
+        type_queue, diff_kind);
+
+  }
+
+  if (kind == abi_util::LinkableMessageKind::RvalueReferenceTypeKind) {
+    return CompareRvalueReferenceTypes(
+        static_cast<const abi_util::RvalueReferenceTypeIR *>(old_type),
+        static_cast<const abi_util::RvalueReferenceTypeIR *>(new_type),
+        type_queue, diff_kind);
+  }
+
+  if (kind == abi_util::LinkableMessageKind::PointerTypeKind) {
+    return ComparePointerTypes(
+        static_cast<const abi_util::PointerTypeIR *>(old_type),
+        static_cast<const abi_util::PointerTypeIR *>(new_type),
+        type_queue, diff_kind);
+  }
+
+  if (kind == abi_util::LinkableMessageKind::RecordTypeKind) {
+    return CompareRecordTypes(
+        static_cast<const abi_util::RecordTypeIR *>(old_type),
+        static_cast<const abi_util::RecordTypeIR *>(new_type),
+        type_queue, diff_kind);
+  }
+  return DiffStatus::no_diff;
+}
+
+static DiffStatus CompareDistinctKindMessages(
+    const abi_util::TypeIR *old_type, const abi_util::TypeIR *new_type) {
+  // For these types to be considered ABI compatible, the very least requirement
+  // is that their sizes and alignments should be equal.
+  // TODO: Fill in
+  return DiffStatus::direct_diff;
+}
+
+DiffStatus DiffWrapperBase::CompareAndDumpTypeDiff(
+    const std::string &old_type_str, const std::string &new_type_str,
+    std::deque<std::string> *type_queue,
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  // If either of the types are not found in their respective maps, the type
+  // was not exposed in a public header and we do a simple string comparison.
+  // Any diff found using a simple string comparison will be a direct diff.
+
+  // Check the map for types which have already been compared
+  bool same_type_str = (old_type_str == new_type_str);
+  if (same_type_str) {
+    // These types have already been diffed, return without further comparison.
+    if (!type_cache_->insert(old_type_str).second) {
+      return DiffStatus::no_diff;
+    }
+    type_queue->push_back(old_type_str);
+  }
+  std::map<std::string, const abi_util::TypeIR *>::const_iterator old_it =
+      old_types_.find(old_type_str);
+  std::map<std::string, const abi_util::TypeIR *>::const_iterator new_it =
+      new_types_.find(new_type_str);
+  if (old_it == old_types_.end() || new_it == new_types_.end()) {
+    // Do a simple string comparison.
+    if (!type_queue->empty()) {
+      type_queue->pop_back();
+    }
+    return (old_type_str == new_type_str) ?
+        DiffStatus::no_diff : DiffStatus::direct_diff;
+  }
+  abi_util::LinkableMessageKind old_kind =
+      old_it->second->GetKind();
+  abi_util::LinkableMessageKind new_kind =
+      new_it->second->GetKind();
+  DiffStatus diff_status = DiffStatus::no_diff;
+  if (old_kind != new_kind) {
+    diff_status = CompareDistinctKindMessages(old_it->second, new_it->second);
+  } else {
+    diff_status = CompareAndDumpTypeDiff(old_it->second , new_it->second ,
+                                         old_kind, type_queue, diff_kind);
+  }
+  if (!type_queue->empty()) {
+    type_queue->pop_back();
+  }
+  return diff_status;
+}
+
+template <>
+bool DiffWrapper<abi_util::RecordTypeIR>::DumpDiff(
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  std::deque<std::string> type_queue;
+  if (oldp_->GetName() != newp_->GetName()) {
+    llvm::errs() << "Comparing two different unreferenced records\n";
+    return false;
+  }
+  if (!type_cache_->insert(oldp_->GetName()).second) {
     return true;
   }
-  return false;
+  CompareRecordTypes(oldp_, newp_, &type_queue, diff_kind);
+  return true;
 }
 
 template <>
-std::unique_ptr<RecordDeclDiff>
-DiffWrapper<RecordDecl, RecordDeclDiff>::Get() {
-  std::unique_ptr<RecordDeclDiff> record_diff(new RecordDeclDiff());
-  assert(oldp_->basic_abi().linker_set_key() ==
-         newp_->basic_abi().linker_set_key());
-  record_diff->set_name(oldp_->basic_abi().name());
-  google::protobuf::RepeatedPtrField<RecordFieldDeclDiff> *fdiffs =
-      record_diff->mutable_field_diffs();
-  google::protobuf::RepeatedPtrField<CXXBaseSpecifierDiff> *bdiffs =
-      record_diff->mutable_base_diffs();
-  google::protobuf::RepeatedPtrField<CXXVTableDiff> *vtdiffs =
-      record_diff->mutable_vtable_diffs();
-  assert(fdiffs != nullptr && bdiffs != nullptr);
-  // Template Information isn't diffed since the linker_set_key includes the
-  // mangled name which includes template information.
-  if (GetElementDiffs(fdiffs, oldp_->fields(), newp_->fields()) ||
-      GetElementDiffs(bdiffs, oldp_->base_specifiers(),
-                      newp_->base_specifiers()) ||
-      GetElementDiffs(vtdiffs, oldp_->vtable_layout().vtable_components(),
-                      newp_->vtable_layout().vtable_components()) ||
-      DiffBasicNamedAndTypedDecl(
-          record_diff->mutable_type_diff()->mutable_old(),
-          record_diff->mutable_type_diff()->mutable_new_(),
-          oldp_->basic_abi(), newp_->basic_abi())) {
-    return record_diff;
+bool DiffWrapper<abi_util::EnumTypeIR>::DumpDiff(
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  std::deque<std::string> type_queue;
+  if (oldp_->GetName() != newp_->GetName()) {
+    llvm::errs() << "Comparing two different unreferenced enums\n";
+    return false;
   }
-  return nullptr;
+  if (!type_cache_->insert(oldp_->GetName()).second) {
+    return true;
+  }
+  CompareEnumTypes(oldp_, newp_, &type_queue, diff_kind);
+  return true;
 }
 
 template <>
-std::unique_ptr<EnumDeclDiff>
-DiffWrapper<EnumDecl, EnumDeclDiff>::Get() {
-  std::unique_ptr<EnumDeclDiff> enum_diff(new EnumDeclDiff());
-  assert(oldp_->basic_abi().linker_set_key() ==
-         newp_->basic_abi().linker_set_key());
-  google::protobuf::RepeatedPtrField<EnumFieldDeclDiff> *fdiffs =
-      enum_diff->mutable_field_diffs();
-  assert(fdiffs != nullptr);
-  enum_diff->set_name(oldp_->basic_abi().name());
-  if (GetElementDiffs(fdiffs, oldp_->enum_fields(), newp_->enum_fields()) ||
-      DiffBasicNamedAndTypedDecl(
-          enum_diff->mutable_type_diff()->mutable_old(),
-          enum_diff->mutable_type_diff()->mutable_new_(),
-          oldp_->basic_abi(), newp_->basic_abi())) {
-    return enum_diff;
+bool DiffWrapper<abi_util::GlobalVarIR>::DumpDiff(
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  std::deque<std::string> type_queue;
+  type_queue.push_back(oldp_->GetName());
+  DiffStatus type_diff = CompareAndDumpTypeDiff(oldp_->GetReferencedType(),
+                                                newp_->GetReferencedType(),
+                                                &type_queue, diff_kind);
+  DiffStatus access_diff = (oldp_->GetAccess() == newp_->GetAccess()) ?
+      DiffStatus::no_diff : DiffStatus::direct_diff;
+  if ((type_diff | access_diff) & DiffStatus::direct_diff) {
+    abi_util::GlobalVarDiffIR global_var_diff_ir(oldp_, newp_);
+    global_var_diff_ir.SetName(oldp_->GetName());
+    return ir_diff_dumper_->AddDiffMessageIR(&global_var_diff_ir,
+                                             Unwind(&type_queue), diff_kind);
   }
-  return nullptr;
+  return true;
 }
 
 template <>
-std::unique_ptr<FunctionDeclDiff>
-DiffWrapper<FunctionDecl, FunctionDeclDiff>::Get() {
-  std::unique_ptr<FunctionDeclDiff> func_diff(new FunctionDeclDiff());
-  google::protobuf::RepeatedPtrField<ParamDeclDiff> *pdiffs =
-      func_diff->mutable_param_diffs();
-  assert(func_diff->mutable_return_type_diffs() != nullptr);
-  func_diff->set_name(oldp_->basic_abi().linker_set_key());
-  if (DiffBasicNamedAndTypedDecl(
-          func_diff->mutable_return_type_diffs()->mutable_old(),
-          func_diff->mutable_return_type_diffs()->mutable_new_(),
-          oldp_->basic_abi(), newp_->basic_abi()) ||
-      GetElementDiffs(pdiffs, oldp_->parameters(), newp_->parameters())) {
-    return func_diff;
-  }
-  return nullptr;
-}
+bool DiffWrapper<abi_util::FunctionIR>::DumpDiff(
+    abi_util::IRDiffDumper::DiffKind diff_kind) {
+  std::deque<std::string> type_queue;
+  type_queue.push_back(oldp_->GetName());
+  DiffStatus param_diffs = CompareFunctionParameters(oldp_->GetParameters(),
+                                                     newp_->GetParameters(),
+                                                     &type_queue, diff_kind);
+  DiffStatus return_type_diff =
+      CompareAndDumpTypeDiff(oldp_->GetReturnType(),
+                             newp_->GetReturnType(),
+                             &type_queue, diff_kind);
+  CompareTemplateInfo(oldp_->GetTemplateElements(),
+                      newp_->GetTemplateElements(),
+                      &type_queue, diff_kind);
 
-template <>
-std::unique_ptr<GlobalVarDeclDiff>
-DiffWrapper<GlobalVarDecl, GlobalVarDeclDiff>::Get() {
-  std::unique_ptr<GlobalVarDeclDiff> global_var_diff(new GlobalVarDeclDiff());
-  assert(global_var_diff->mutable_type_diff() != nullptr);
-  if (DiffBasicNamedAndTypedDecl(
-          global_var_diff->mutable_type_diff()->mutable_old(),
-          global_var_diff->mutable_type_diff()->mutable_new_(),
-          oldp_->basic_abi(), newp_->basic_abi())) {
-    return global_var_diff;
+  if ((param_diffs == DiffStatus::direct_diff ||
+       return_type_diff == DiffStatus::direct_diff) ||
+      (oldp_->GetAccess() != newp_->GetAccess())) {
+    abi_util::FunctionDiffIR function_diff_ir(oldp_, newp_);
+    function_diff_ir.SetName(oldp_->GetName());
+    return ir_diff_dumper_->AddDiffMessageIR(&function_diff_ir,
+                                             Unwind(&type_queue), diff_kind);
   }
-  return nullptr;
+  return true;
 }
-
 } // abi_diff_wrappers
diff --git a/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.h b/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.h
index 8cf4699..9b0a7f5 100644
--- a/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.h
+++ b/vndk/tools/header-checker/header-abi-diff/src/abi_diff_wrappers.h
@@ -22,45 +22,160 @@
 #include "proto/abi_diff.pb.h"
 #pragma clang diagnostic pop
 
+#include <ir_representation.h>
+
+#include <deque>
+
 namespace abi_diff_wrappers {
 
-template <typename T>
+template <typename T, typename F>
 static bool IgnoreSymbol(const T *element,
-                         const std::set<std::string> &ignored_symbols) {
-  return ignored_symbols.find(element->basic_abi().linker_set_key()) !=
+                         const std::set<std::string> &ignored_symbols,
+                         F func) {
+  return ignored_symbols.find(func(element)) !=
       ignored_symbols.end();
 }
 
-template <typename T, typename TDiff>
-class DiffWrapperBase {
- public:
-  virtual std::unique_ptr<TDiff> Get() = 0 ;
- protected:
-  DiffWrapperBase(const T *oldp, const T *newp) : oldp_(oldp), newp_(newp) { }
-  template <typename Element, typename ElementDiff>
-  bool GetElementDiffs(
-      google::protobuf::RepeatedPtrField<ElementDiff> *dst,
-      const google::protobuf::RepeatedPtrField<Element> &old_elements,
-      const google::protobuf::RepeatedPtrField<Element> &new_elements);
-
- private:
-  template <typename Element, typename ElementDiff>
-  void GetExtraElementDiffs(
-      google::protobuf::RepeatedPtrField<ElementDiff> *dst, int i, int j,
-      const google::protobuf::RepeatedPtrField<Element> &old_elements,
-      const google::protobuf::RepeatedPtrField<Element> &new_elements);
-
- protected:
-  const T *oldp_;
-  const T *newp_;
+enum DiffStatus {
+  // Previous stages of CompareAndTypeDiff should not dump the diff.
+  no_diff = 0,
+  // Previous stages of CompareAndTypeDiff should dump the diff if required.
+  direct_diff = 1,
 };
 
-template <typename T, typename TDiff>
-class DiffWrapper : public DiffWrapperBase<T, TDiff> {
+class DiffWrapperBase {
  public:
-  DiffWrapper(const T *oldp, const T *newp)
-      : DiffWrapperBase<T, TDiff>(oldp, newp) { }
-  std::unique_ptr<TDiff> Get() override;
+  virtual bool DumpDiff(abi_util::IRDiffDumper::DiffKind diff_kind) = 0;
+  virtual ~DiffWrapperBase() { }
+ protected:
+  DiffWrapperBase(
+      abi_util::IRDiffDumper *ir_diff_dumper,
+      const std::map<std::string, const abi_util::TypeIR *> &old_types,
+      const std::map<std::string, const abi_util::TypeIR *> &new_types,
+      std::set<std::string> *type_cache)
+      : ir_diff_dumper_(ir_diff_dumper),
+        old_types_(old_types), new_types_(new_types),
+        type_cache_(type_cache) { }
+
+  DiffStatus CompareAndDumpTypeDiff(const std::string &old_type_str,
+                                    const std::string &new_type_str,
+                                    std::deque<std::string> *type_queue,
+                                    abi_util::IRDiffDumper::DiffKind diff_kind);
+
+  DiffStatus CompareAndDumpTypeDiff(
+      const abi_util::TypeIR *old_type, const abi_util::TypeIR *new_type,
+      abi_util::LinkableMessageKind kind, std::deque<std::string> *type_queue,
+      abi_util::IRDiffDumper::DiffKind diff_kind);
+
+
+  DiffStatus CompareRecordTypes(const abi_util::RecordTypeIR *old_type,
+                                const abi_util::RecordTypeIR *new_type,
+                                std::deque<std::string> *type_queue,
+                                abi_util::IRDiffDumper::DiffKind diff_kind);
+
+  DiffStatus CompareQualifiedTypes(const abi_util::QualifiedTypeIR *old_type,
+                                   const abi_util::QualifiedTypeIR *new_type,
+                                   std::deque<std::string> *type_queue,
+                                   abi_util::IRDiffDumper::DiffKind diff_kind);
+
+  DiffStatus ComparePointerTypes(const abi_util::PointerTypeIR *old_type,
+                                 const abi_util::PointerTypeIR *new_type,
+                                 std::deque<std::string> *type_queue,
+                                 abi_util::IRDiffDumper::DiffKind diff_kind);
+
+  DiffStatus CompareLvalueReferenceTypes(
+      const abi_util::LvalueReferenceTypeIR *old_type,
+      const abi_util::LvalueReferenceTypeIR *new_type,
+      std::deque<std::string> *type_queue,
+      abi_util::IRDiffDumper::DiffKind diff_kind);
+
+  DiffStatus CompareRvalueReferenceTypes(
+      const abi_util::RvalueReferenceTypeIR *old_type,
+      const abi_util::RvalueReferenceTypeIR *new_type,
+      std::deque<std::string> *type_queue,
+      abi_util::IRDiffDumper::DiffKind diff_kind);
+
+
+  DiffStatus CompareBuiltinTypes(const abi_util::BuiltinTypeIR *old_type,
+                                 const abi_util::BuiltinTypeIR *new_type);
+  static void CompareEnumFields(
+    const std::vector<abi_util::EnumFieldIR> &old_fields,
+    const std::vector<abi_util::EnumFieldIR> &new_fields,
+    abi_util::EnumTypeDiffIR *enum_type_diff_ir);
+
+  DiffStatus CompareEnumTypes(const abi_util::EnumTypeIR *old_type,
+                              const abi_util::EnumTypeIR *new_type,
+                              std::deque<std::string> *type_queue,
+                              abi_util::IRDiffDumper::DiffKind diff_kind);
+
+  std::unique_ptr<abi_util::RecordFieldDiffIR> CompareCommonRecordFields(
+    const abi_util::RecordFieldIR *old_field,
+    const abi_util::RecordFieldIR *new_field,
+    std::deque<std::string> *type_queue,
+    abi_util::IRDiffDumper::DiffKind diff_kind);
+
+  std::pair<std::vector<abi_util::RecordFieldDiffIR>,
+      std::vector<const abi_util::RecordFieldIR *>>
+  CompareRecordFields(
+      const std::vector<abi_util::RecordFieldIR> &old_fields,
+      const std::vector<abi_util::RecordFieldIR> &new_fields,
+      std::deque<std::string> *type_queue,
+      abi_util::IRDiffDumper::DiffKind diff_kind);
+
+  DiffStatus CompareFunctionParameters(
+      const std::vector<abi_util::ParamIR> &old_parameters,
+      const std::vector<abi_util::ParamIR> &new_parameters,
+      std::deque<std::string> *type_queue,
+      abi_util::IRDiffDumper::DiffKind diff_kind);
+
+  bool CompareBaseSpecifiers(
+      const std::vector<abi_util::CXXBaseSpecifierIR> &old_base_specifiers,
+      const std::vector<abi_util::CXXBaseSpecifierIR> &new_base_specifiers,
+      std::deque<std::string> *type_queue,
+      abi_util::IRDiffDumper::DiffKind diff_kind);
+
+  bool CompareVTables(const abi_util::RecordTypeIR *old_record,
+                      const abi_util::RecordTypeIR *new_record);
+
+  bool CompareVTableComponents(
+      const abi_util::VTableComponentIR &old_component,
+      const abi_util::VTableComponentIR &new_component);
+
+  void CompareTemplateInfo(
+      const std::vector<abi_util::TemplateElementIR> &old_template_elements,
+      const std::vector<abi_util::TemplateElementIR> &new_template_elements,
+      std::deque<std::string> *type_queue,
+      abi_util::IRDiffDumper::DiffKind diff_kind);
+
+
+  bool CompareSizeAndAlignment(const abi_util::TypeIR *old_ti,
+                               const abi_util::TypeIR *new_ti);
+
+  template <typename DiffType, typename DiffElement>
+  bool AddToDiff(DiffType *mutable_diff, const DiffElement *oldp,
+                 const DiffElement *newp,
+                 std::deque<std::string> *type_queue = nullptr);
+ protected:
+  abi_util::IRDiffDumper *ir_diff_dumper_;
+  const std::map<std::string, const abi_util::TypeIR *> &old_types_;
+  const std::map<std::string, const abi_util::TypeIR *> &new_types_;
+  std::set<std::string> *type_cache_;
+};
+
+template <typename T>
+class DiffWrapper : public DiffWrapperBase {
+ public:
+  DiffWrapper(const T *oldp, const T *newp,
+              abi_util::IRDiffDumper *ir_diff_dumper,
+              const std::map<std::string, const abi_util::TypeIR *> &old_types,
+              const std::map<std::string, const abi_util::TypeIR *> &new_types,
+              std::set<std::string> *type_cache)
+      : DiffWrapperBase(ir_diff_dumper, old_types, new_types, type_cache),
+        oldp_(oldp), newp_(newp) { }
+  bool DumpDiff(abi_util::IRDiffDumper::DiffKind diff_kind) override;
+ private:
+  const T *oldp_;
+  const T *newp_;
 };
 
 } // abi_diff_wrappers
diff --git a/vndk/tools/header-checker/header-abi-diff/src/header_abi_diff.cpp b/vndk/tools/header-checker/header-abi-diff/src/header_abi_diff.cpp
index 7281c09..813ea75 100644
--- a/vndk/tools/header-checker/header-abi-diff/src/header_abi_diff.cpp
+++ b/vndk/tools/header-checker/header-abi-diff/src/header_abi_diff.cpp
@@ -14,6 +14,8 @@
 
 #include "abi_diff.h"
 
+#include <fstream>
+
 #include <llvm/Support/CommandLine.h>
 #include <llvm/Support/FileSystem.h>
 #include <llvm/Support/raw_ostream.h>
@@ -49,6 +51,12 @@
     "advice-only", llvm::cl::desc("Advisory mode only"), llvm::cl::Optional,
     llvm::cl::cat(header_checker_category));
 
+static llvm::cl::opt<bool> check_all_apis(
+    "check-all-apis",
+    llvm::cl::desc("All apis, whether referenced or not, by exported symbols in"
+                   " the dynsym table of a shared library are checked"),
+    llvm::cl::Optional, llvm::cl::cat(header_checker_category));
+
 static llvm::cl::opt<bool> suppress_local_warnings(
     "suppress_local_warnings", llvm::cl::desc("suppress local warnings"),
     llvm::cl::Optional, llvm::cl::cat(header_checker_category));
@@ -58,6 +66,13 @@
     llvm::cl::desc("Do not return a non zero status on extensions"),
     llvm::cl::Optional, llvm::cl::cat(header_checker_category));
 
+static llvm::cl::opt<bool> allow_unreferenced_changes(
+    "allow-unreferenced-changes",
+    llvm::cl::desc("Do not return a non zero status on changes to data"
+                   " structures which are not directly referenced by exported"
+                   " APIs."),
+    llvm::cl::Optional, llvm::cl::cat(header_checker_category));
+
 static std::set<std::string> LoadIgnoredSymbols(std::string &symbol_list_path) {
   std::ifstream symbol_ifstream(symbol_list_path);
   std::set<std::string> ignored_symbols;
@@ -80,38 +95,50 @@
     ignored_symbols = LoadIgnoredSymbols(ignore_symbol_list);
   }
   HeaderAbiDiff judge(lib_name, arch, old_dump, new_dump, compatibility_report,
-                      ignored_symbols);
+                      ignored_symbols, check_all_apis);
 
-  CompatibilityStatus status  = judge.GenerateCompatibilityReport();
+  abi_util::CompatibilityStatusIR status = judge.GenerateCompatibilityReport();
 
   std::string status_str = "";
-  switch (status) {
-    case CompatibilityStatus::INCOMPATIBLE:
-      status_str = "broken";
-      break;
-    case CompatibilityStatus::EXTENSION:
-      status_str = "extended";
-      break;
-    default:
-      break;
-  }
+  std::string unreferenced_change_str = "";
+  std::string error_or_warning_str = "\033[36;1mwarning: \033[0m";
 
+  if (status == abi_util::CompatibilityStatusIR::Incompatible) {
+    error_or_warning_str = "\033[31;1merror: \033[0m";
+    status_str = " INCOMPATIBLE CHANGES";
+  } else if (status & abi_util::CompatibilityStatusIR::Extension) {
+    status_str = "EXTENDING CHANGES";
+  }
+  if (status & abi_util::CompatibilityStatusIR::UnreferencedChanges) {
+    unreferenced_change_str = ", changes in exported headers, which are";
+    unreferenced_change_str += " not directly referenced by exported symbols.";
+    unreferenced_change_str += " This MIGHT be an ABI breaking change due to";
+    unreferenced_change_str += " internal typecasts.";
+
+  }
   if (!suppress_local_warnings && status) {
     llvm::errs() << "******************************************************\n"
-                 << "VNDK Abi "
+                 << error_or_warning_str
+                 << "VNDK library: "
+                 << lib_name
+                 << "'s ABI has "
                  << status_str
-                 << ":"
+                 << unreferenced_change_str
                  << " Please check compatiblity report at : "
                  << compatibility_report << "\n"
-                 << "*****************************************************\n";
+                 << "******************************************************\n";
+  }
+
+  if ((allow_extensions &&
+      (status & abi_util::CompatibilityStatusIR::Extension)) ||
+      (allow_unreferenced_changes &&
+      (status & abi_util::CompatibilityStatusIR::UnreferencedChanges))) {
+    return abi_util::CompatibilityStatusIR::Compatible;
   }
 
   if (advice_only) {
-    return CompatibilityStatus::COMPATIBLE;
+    return abi_util::CompatibilityStatusIR::Compatible;
   }
 
-  if (allow_extensions && status == CompatibilityStatus::EXTENSION) {
-    return CompatibilityStatus::COMPATIBLE;
-  }
   return status;
 }
diff --git a/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.cpp b/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.cpp
index 32bb3c7..b0d4e23 100644
--- a/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.cpp
+++ b/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.cpp
@@ -28,10 +28,26 @@
 ABIWrapper::ABIWrapper(
     clang::MangleContext *mangle_contextp,
     clang::ASTContext *ast_contextp,
-    const clang::CompilerInstance *cip)
+    const clang::CompilerInstance *cip,
+    std::set<std::string> *type_cache,
+    abi_util::IRDumper *ir_dumper,
+    std::map<const clang::Decl *, std::string> &decl_to_source_cache)
   : cip_(cip),
     mangle_contextp_(mangle_contextp),
-    ast_contextp_(ast_contextp) { }
+    ast_contextp_(ast_contextp),
+    type_cache_(type_cache),
+    ir_dumper_(ir_dumper),
+    decl_to_source_file_cache_(decl_to_source_cache) { }
+
+std::string ABIWrapper::GetCachedDeclSourceFile(
+    const clang::Decl *decl, const clang::CompilerInstance *cip) {
+  assert(decl != nullptr);
+  auto result = decl_to_source_file_cache_.find(decl);
+  if (result == decl_to_source_file_cache_.end()) {
+    return GetDeclSourceFile(decl, cip);
+  }
+  return result->second;
+}
 
 std::string ABIWrapper::GetDeclSourceFile(const clang::Decl *decl,
                                           const clang::CompilerInstance *cip) {
@@ -53,85 +69,174 @@
   return file_abs_path;
 }
 
-abi_dump::AccessSpecifier ABIWrapper::AccessClangToDump(
-    const clang::AccessSpecifier sp) const {
+static abi_util::AccessSpecifierIR AccessClangToIR(
+    const clang::AccessSpecifier sp)  {
   switch (sp) {
     case clang::AS_private: {
-      return abi_dump::AccessSpecifier::private_access;
+      return abi_util::AccessSpecifierIR::PrivateAccess;
       break;
     }
     case clang::AS_protected: {
-      return abi_dump::AccessSpecifier::protected_access;
+      return abi_util::AccessSpecifierIR::ProtectedAccess;
       break;
     }
     default: {
-      return abi_dump::AccessSpecifier::public_access;
+      return abi_util::AccessSpecifierIR::PublicAccess;
       break;
     }
   }
 }
 
-// Dumping the size and alignment is optional. This is since clang can lazily
-// instantiate records as incomplete and therefore their sizes 'may' not be
-// computable. b/62307940
-bool ABIWrapper::SetupBasicTypeAbi(abi_dump::BasicTypeAbi *type_abi,
-                                   const clang::QualType type,
-                                   bool dump_size) const {
-  if (!type_abi) {
+// Get type 'referenced' by qual_type. Referenced type implies, in order:
+// 1) Strip off all qualifiers if qual_type has CVR qualifiers.
+// 2) Strip off a pointer level if qual_type is a pointer.
+// 3) Strip off the reference if qual_type is a reference.
+// Note: qual_type is expected to be a canonical type.
+clang::QualType ABIWrapper::GetReferencedType(const clang::QualType qual_type) {
+  const clang::Type *type_ptr = qual_type.getTypePtr();
+  if (qual_type.hasLocalQualifiers()) {
+    return qual_type.getLocalUnqualifiedType();
+  }
+  if (type_ptr->isPointerType()) {
+    return type_ptr->getPointeeType();
+  }
+  if (type_ptr->isArrayType()) {
+    return
+        type_ptr->getArrayElementTypeNoTypeQual()->getCanonicalTypeInternal();
+  }
+  return qual_type.getNonReferenceType();
+}
+
+bool ABIWrapper::CreateExtendedType(
+    clang::QualType qual_type,
+    abi_util::TypeIR *typep) {
+  std::string type_name = QualTypeToString(qual_type);
+  if (!type_cache_->insert(type_name).second) {
+    return true;
+  }
+  const clang::QualType canonical_type = qual_type.getCanonicalType();
+  return CreateBasicNamedAndTypedDecl(canonical_type, typep, "");
+}
+
+//This overload takes in a qualtype and adds its information to the abi-dump on
+//its own.
+bool ABIWrapper::CreateBasicNamedAndTypedDecl(clang::QualType qual_type,
+                                              const std::string &source_file) {
+  std::string type_name = QualTypeToString(qual_type);
+  const clang::QualType canonical_type = qual_type.getCanonicalType();
+  const clang::Type *base_type = canonical_type.getTypePtr();
+  bool is_ptr = base_type->isPointerType();
+  bool is_reference = base_type->isReferenceType();
+  bool is_array = base_type->isArrayType();
+  bool is_builtin = base_type->isBuiltinType();
+  bool has_referenced_type =
+      is_ptr || is_reference || is_array ||
+      canonical_type.hasLocalQualifiers() || is_builtin;
+  if (!has_referenced_type || !type_cache_->insert(type_name).second) {
+    return true;
+  }
+  // Do something similar to what is being done right now. Create an object
+  // extending Type and return a pointer to that and pass it to CreateBasic...
+  // CreateBasic...(qualtype, Type *) fills in size, alignemnt etc.
+  std::unique_ptr<abi_util::TypeIR> typep = SetTypeKind(canonical_type,
+                                                        source_file);
+  if (!base_type->isVoidType() && !typep) {
     return false;
   }
-  const clang::QualType canonical_type = type.getCanonicalType();
-  type_abi->set_name(QualTypeToString(canonical_type));
+  return CreateBasicNamedAndTypedDecl(canonical_type, typep.get(),
+                                      source_file) &&
+      ir_dumper_->AddLinkableMessageIR(typep.get());
+}
+
+// CreateBasicNamedAndTypedDecl creates a BasicNamedAndTypedDecl : that'll
+// include all the generic information a basic type will have:
+// abi_dump::BasicNamedAndTypedDecl. Other methods fill in more specific
+// information, eg: RecordDecl, EnumDecl.
+bool ABIWrapper::CreateBasicNamedAndTypedDecl(
+    clang::QualType canonical_type,
+    abi_util::TypeIR *typep, const std::string &source_file) {
   // Cannot determine the size and alignment for template parameter dependent
   // types as well as incomplete types.
   const clang::Type *base_type = canonical_type.getTypePtr();
+  assert(base_type != nullptr);
   clang::Type::TypeClass type_class = base_type->getTypeClass();
   // Temporary Hack for auto type sizes. Not determinable.
-  if (dump_size && base_type && !(base_type->isDependentType()) &&
-      !(base_type->isIncompleteType()) && (type_class != clang::Type::Auto)) {
+  if ((type_class != clang::Type::Auto) && !base_type->isIncompleteType() &&
+      !(base_type->isDependentType())) {
     std::pair<clang::CharUnits, clang::CharUnits> size_and_alignment =
     ast_contextp_->getTypeInfoInChars(canonical_type);
-    int64_t size = size_and_alignment.first.getQuantity();
-    int64_t alignment = size_and_alignment.second.getQuantity();
-    type_abi->set_size(size);
-    type_abi->set_alignment(alignment);
+    size_t size = size_and_alignment.first.getQuantity();
+    size_t alignment = size_and_alignment.second.getQuantity();
+    typep->SetSize(size);
+    typep->SetAlignment(alignment);
   }
-  return true;
+  typep->SetName(QualTypeToString(canonical_type));
+  typep->SetLinkerSetKey(QualTypeToString(canonical_type));
+  // default values are false, we don't set them since explicitly doing that
+  // makes the abi dumps more verbose.
+  // This type has a reference type if its a pointer / reference OR it has CVR
+  // qualifiers.
+  clang::QualType referenced_type = GetReferencedType(canonical_type);
+  typep->SetReferencedType(QualTypeToString(referenced_type));
+  // Create the type for referenced type.
+  return CreateBasicNamedAndTypedDecl(referenced_type, source_file);
 }
 
-bool ABIWrapper::SetupBasicNamedAndTypedDecl(
-    abi_dump::BasicNamedAndTypedDecl *basic_named_and_typed_decl,
-    const clang::QualType type, const std::string &name,
-    const clang::AccessSpecifier &access, std::string key,
-    bool dump_size) const {
-  if (!basic_named_and_typed_decl) {
-    return false;
-  }
-  abi_dump::AccessSpecifier access_dump = AccessClangToDump(access);
-  basic_named_and_typed_decl->set_name(name);
-  basic_named_and_typed_decl->set_access(access_dump);
-  if (key != "") {
-    basic_named_and_typed_decl->set_linker_set_key(key);
-  }
-  return SetupBasicTypeAbi(basic_named_and_typed_decl->mutable_type_abi(),
-                           type, dump_size);
-}
-
-static bool ShouldDumpSize(clang::QualType qt) {
-  const clang::Type *type_ptr = qt.getTypePtr();
-  assert(type_ptr != nullptr);
-  if (type_ptr->isBuiltinType() || type_ptr->isPointerType()) {
-    return true;
-  }
-  return false;
-}
-
-std::string ABIWrapper::GetTypeLinkageName(const clang::Type *typep) const {
+std::string ABIWrapper::GetTypeLinkageName(const clang::Type *typep)  {
   assert(typep != nullptr);
   clang::QualType qt = typep->getCanonicalTypeInternal();
   return QualTypeToString(qt);
 }
 
+std::unique_ptr<abi_util::TypeIR> ABIWrapper::SetTypeKind(
+    const clang::QualType canonical_type, const std::string &source_file) {
+  if (canonical_type.hasLocalQualifiers()) {
+    auto qual_type_ir =
+        std::make_unique<abi_util::QualifiedTypeIR>();
+    qual_type_ir->SetConstness(canonical_type.isConstQualified());
+    qual_type_ir->SetRestrictedness(canonical_type.isRestrictQualified());
+    qual_type_ir->SetVolatility(canonical_type.isVolatileQualified());
+    qual_type_ir->SetSourceFile(source_file);
+    return qual_type_ir;
+  }
+  const clang::Type *type_ptr = canonical_type.getTypePtr();
+  if (type_ptr->isPointerType()) {
+    auto pointer_type_ir = std::make_unique<abi_util::PointerTypeIR>();
+    pointer_type_ir->SetSourceFile(source_file);
+    return pointer_type_ir;
+  }
+  if (type_ptr->isLValueReferenceType()) {
+    auto lvalue_reference_type_ir =
+        std::make_unique<abi_util::LvalueReferenceTypeIR>();
+    lvalue_reference_type_ir->SetSourceFile(source_file);
+    return lvalue_reference_type_ir;
+  }
+  if (type_ptr->isRValueReferenceType()) {
+   auto rvalue_reference_type_ir =
+       std::make_unique<abi_util::RvalueReferenceTypeIR>();
+   rvalue_reference_type_ir->SetSourceFile(source_file);
+   return rvalue_reference_type_ir;
+  }
+  if (type_ptr->isArrayType()) {
+    auto array_type_ir = std::make_unique<abi_util::ArrayTypeIR>();
+    array_type_ir->SetSourceFile(source_file);
+    return array_type_ir;
+  }
+  if (type_ptr->isEnumeralType()) {
+    return std::make_unique<abi_util::EnumTypeIR>();
+  }
+  if (type_ptr->isRecordType()) {
+    return std::make_unique<abi_util::RecordTypeIR>();
+  }
+  if (type_ptr->isBuiltinType()) {
+    auto builtin_type_ir = std::make_unique<abi_util::BuiltinTypeIR>();
+    builtin_type_ir->SetSignedness(type_ptr->isUnsignedIntegerType());
+    builtin_type_ir->SetIntegralType(type_ptr->isIntegralType(*ast_contextp_));
+    return builtin_type_ir;
+  }
+  return nullptr;
+}
+
 std::string ABIWrapper::GetMangledNameDecl(
     const clang::NamedDecl *decl, clang::MangleContext *mangle_contextp) {
   if (!mangle_contextp->shouldMangleDeclName(decl)) {
@@ -145,36 +250,8 @@
   return mangled_name;
 }
 
-bool ABIWrapper::SetupTemplateParamNames(
-    abi_dump::TemplateInfo *tinfo,
-    clang::TemplateParameterList *pl) const {
-  if (tinfo->elements_size() > 0) {
-    return true;
-  }
-
-  clang::TemplateParameterList::iterator template_it = pl->begin();
-  while (template_it != pl->end()) {
-    abi_dump::TemplateElement *template_parameterp =
-        tinfo->add_elements();
-    if (!template_parameterp) {
-      return false;
-    }
-    abi_dump::TemplateElement::BasicTemplateElementAbi *basic_abi =
-        template_parameterp->mutable_basic_abi();
-    if (!basic_abi) {
-      return false;
-    }
-    std::string name = (*template_it)->getName();
-    basic_abi->set_name(name);
-    // TODO : Default arg ?
-    basic_abi->set_linker_set_key(name);
-    template_it++;
-  }
-  return true;
-}
-
 std::string ABIWrapper::GetTagDeclQualifiedName(
-    const clang::TagDecl *decl) const {
+    const clang::TagDecl *decl) {
   if (decl->getTypedefNameForAnonDecl()) {
     return decl->getTypedefNameForAnonDecl()->getQualifiedNameAsString();
   }
@@ -182,8 +259,10 @@
 }
 
 bool ABIWrapper::SetupTemplateArguments(
-    abi_dump::TemplateInfo *tinfo,
-    const clang::TemplateArgumentList *tl) const {
+    const clang::TemplateArgumentList *tl,
+    abi_util::TemplatedArtifactIR *ta,
+    const std::string &source_file) {
+  abi_util::TemplateInfoIR template_info;
   for (int i = 0; i < tl->size(); i++) {
     const clang::TemplateArgument &arg = (*tl)[i];
     //TODO: More comprehensive checking needed.
@@ -191,25 +270,33 @@
       continue;
     }
     clang::QualType type = arg.getAsType();
-    abi_dump::TemplateElement *template_parameterp =
-        tinfo->add_elements();
-    if (!template_parameterp) {
+    template_info.AddTemplateElement(
+        abi_util::TemplateElementIR(QualTypeToString(type)));
+    if (!CreateBasicNamedAndTypedDecl(type, source_file)) {
       return false;
     }
-    abi_dump::TemplateElement::BasicTemplateElementAbi *basic_abi =
-        template_parameterp->mutable_basic_abi();
-    if (!basic_abi || !SetupBasicTypeAbi(basic_abi->mutable_type_abi(), type,
-                                         false)) {
-      return false;
-    }
-    // TODO : default arg
-    basic_abi->set_linker_set_key(QualTypeToString(type));
   }
+  ta->SetTemplateInfo(std::move(template_info));
   return true;
 }
 
+static const clang::EnumDecl *GetAnonymousEnum(
+    const clang::QualType qual_type) {
+  const clang::Type *type_ptr = qual_type.getTypePtr();
+  assert(type_ptr != nullptr);
+  const clang::TagDecl *tag_decl = type_ptr->getAsTagDecl();
+  if (!tag_decl) {
+    return nullptr;
+  }
+  const clang::EnumDecl *enum_decl = llvm::dyn_cast<clang::EnumDecl>(tag_decl);
+  if (!enum_decl || enum_decl->hasNameForLinkage()) {
+    return nullptr;
+  }
+  return enum_decl;
+}
+
 std::string ABIWrapper::QualTypeToString(
-    const clang::QualType &sweet_qt) const {
+    const clang::QualType &sweet_qt) {
   const clang::QualType salty_qt = sweet_qt.getCanonicalType();
   // clang::TypeName::getFullyQualifiedName removes the part of the type related
   // to it being a template parameter. Don't use it for dependent types.
@@ -223,75 +310,84 @@
     clang::MangleContext *mangle_contextp,
     clang::ASTContext *ast_contextp,
     const clang::CompilerInstance *compiler_instance_p,
-    const clang::FunctionDecl *decl)
-  : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
+    const clang::FunctionDecl *decl,
+    std::set<std::string> *type_cache,
+    abi_util::IRDumper *ir_dumper,
+    std::map<const clang::Decl *, std::string> &decl_to_source_cache)
+  : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p,
+               type_cache, ir_dumper, decl_to_source_cache),
     function_decl_(decl) { }
 
+bool FunctionDeclWrapper::SetupThisParameter(abi_util::FunctionIR *functionp,
+                                             const std::string &source_file) {
+  const clang::CXXMethodDecl *cxx_method_decl =
+      llvm::dyn_cast<clang::CXXMethodDecl>(function_decl_);
+  // No this pointer for static methods.
+  if (!cxx_method_decl || cxx_method_decl->isStatic()) {
+    return true;
+  }
+  clang::QualType this_type = cxx_method_decl->getThisType(*ast_contextp_);
+  return SetupFunctionParameter(functionp, this_type, false, source_file);
+}
+
+bool FunctionDeclWrapper::SetupFunctionParameter(
+    abi_util::FunctionIR *functionp, const clang::QualType qual_type,
+    bool has_default_arg, const std::string &source_file) {
+  if (!CreateBasicNamedAndTypedDecl(qual_type, source_file)) {
+    return false;
+  }
+  functionp->AddParameter(abi_util::ParamIR(QualTypeToString(qual_type),
+                                            has_default_arg));
+  return true;
+}
+
 bool FunctionDeclWrapper::SetupFunctionParameters(
-    abi_dump::FunctionDecl *functionp) const {
+    abi_util::FunctionIR *functionp,
+    const std::string &source_file) {
   clang::FunctionDecl::param_const_iterator param_it =
       function_decl_->param_begin();
+  // If this is a CXXMethodDecl, we need to add the "this" pointer.
+  if (!SetupThisParameter(functionp, source_file)) {
+    return false;
+  }
+
   while (param_it != function_decl_->param_end()) {
-    abi_dump::ParamDecl *function_fieldp = functionp->add_parameters();
-    if (!function_fieldp) {
-      llvm::errs() << "Couldn't add parameter to method. Aborting\n";
-      return false;
-    }
     // The linker set key is blank since that shows up in the mangled name.
     bool has_default_arg = (*param_it)->hasDefaultArg();
     clang::QualType param_qt = (*param_it)->getType();
-    bool should_dump_size = ShouldDumpSize(param_qt);
-    if (!SetupBasicNamedAndTypedDecl(
-        function_fieldp->mutable_basic_abi(),
-        (*param_it)->getType(), (*param_it)->getName(),
-        (*param_it)->getAccess(), has_default_arg ? "true" : "false",
-        should_dump_size)) {
+    if (!SetupFunctionParameter(functionp, param_qt, has_default_arg,
+                                source_file)) {
       return false;
     }
-    function_fieldp->set_default_arg(has_default_arg);
     param_it++;
   }
   return true;
 }
 
-bool FunctionDeclWrapper::SetupFunction(abi_dump::FunctionDecl *functionp,
-                                        const std::string &source_file) const {
+bool FunctionDeclWrapper::SetupFunction(abi_util::FunctionIR *functionp,
+                                        const std::string &source_file)  {
   // Go through all the parameters in the method and add them to the fields.
   // Also get the fully qualfied name.
-  functionp->set_source_file(source_file);
-  // Combine the function name and return type to form a NamedAndTypedDecl
+  functionp->SetSourceFile(source_file);
+  functionp->SetName(function_decl_->getQualifiedNameAsString());
   clang::QualType return_type = function_decl_->getReturnType();
-  bool should_dump_size = ShouldDumpSize(return_type);
-  return SetupBasicNamedAndTypedDecl(
-      functionp->mutable_basic_abi(),
-      return_type, function_decl_->getQualifiedNameAsString(),
-      function_decl_->getAccess(), "", should_dump_size) &&
-      SetupTemplateInfo(functionp) && SetupFunctionParameters(functionp);
+
+  functionp->SetReturnType(QualTypeToString(return_type));
+  functionp->SetAccess(AccessClangToIR(function_decl_->getAccess()));
+  return CreateBasicNamedAndTypedDecl(return_type, source_file) &&
+      SetupFunctionParameters(functionp, source_file) &&
+      SetupTemplateInfo(functionp, source_file);
 }
 
 bool FunctionDeclWrapper::SetupTemplateInfo(
-    abi_dump::FunctionDecl *functionp) const {
+    abi_util::FunctionIR *functionp,
+    const std::string &source_file)  {
   switch (function_decl_->getTemplatedKind()) {
-    case clang::FunctionDecl::TK_FunctionTemplate: {
-      clang::FunctionTemplateDecl *template_decl =
-          function_decl_->getDescribedFunctionTemplate();
-      if (template_decl) {
-        clang::TemplateParameterList *template_parameter_list =
-            template_decl->getTemplateParameters();
-        if (template_parameter_list &&
-            !SetupTemplateParamNames(functionp->mutable_template_info(),
-                                     template_parameter_list)) {
-          return false;
-        }
-      }
-      break;
-    }
     case clang::FunctionDecl::TK_FunctionTemplateSpecialization: {
       const clang::TemplateArgumentList *arg_list =
           function_decl_->getTemplateSpecializationArgs();
-      if (arg_list &&
-          !SetupTemplateArguments(functionp->mutable_template_info(),
-                                  arg_list)) {
+      if (arg_list && !SetupTemplateArguments(arg_list, functionp,
+                                              source_file)) {
         return false;
       }
       break;
@@ -303,11 +399,9 @@
   return true;
 }
 
-std::unique_ptr<abi_dump::FunctionDecl>
-FunctionDeclWrapper::GetFunctionDecl() const {
-  std::unique_ptr<abi_dump::FunctionDecl> abi_decl(
-      new abi_dump::FunctionDecl());
-  std::string source_file = GetDeclSourceFile(function_decl_, cip_);
+std::unique_ptr<abi_util::FunctionIR> FunctionDeclWrapper::GetFunctionDecl() {
+  auto abi_decl = std::make_unique<abi_util::FunctionIR>();
+  std::string source_file = GetCachedDeclSourceFile(function_decl_, cip_);
   if (!SetupFunction(abi_decl.get(), source_file)) {
     return nullptr;
   }
@@ -318,59 +412,110 @@
     clang::MangleContext *mangle_contextp,
     clang::ASTContext *ast_contextp,
     const clang::CompilerInstance *compiler_instance_p,
-    const clang::RecordDecl *decl)
-  : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
-    record_decl_(decl) { }
+    const clang::RecordDecl *decl,
+    std::set<std::string> *type_cache,
+    abi_util::IRDumper *ir_dumper,
+    std::map<const clang::Decl *, std::string> &decl_to_source_cache,
+    const std::string &previous_record_stages)
+  : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p,
+               type_cache, ir_dumper, decl_to_source_cache),
+    record_decl_(decl), previous_record_stages_(previous_record_stages) { }
 
-bool RecordDeclWrapper::SetupRecordFields(abi_dump::RecordDecl *recordp) const {
+bool RecordDeclWrapper::CreateAnonymousRecord(
+    const clang::RecordDecl *record_decl, const std::string &linker_set_key) {
+  RecordDeclWrapper record_decl_wrapper(mangle_contextp_, ast_contextp_, cip_,
+                                        record_decl, type_cache_, ir_dumper_,
+                                        decl_to_source_file_cache_,
+                                        linker_set_key);
+  return record_decl_wrapper.GetRecordDecl();
+}
+
+static const clang::RecordDecl *GetAnonymousRecord(clang::QualType type) {
+  const clang::Type *type_ptr = type.getTypePtr();
+  assert(type_ptr != nullptr);
+  if (!type_ptr->isRecordType()) {
+    return nullptr;
+  }
+  const clang::TagDecl *tag_decl = type_ptr->getAsTagDecl();
+  if (!tag_decl) {
+    return nullptr;
+  }
+  const clang::RecordDecl *record_decl =
+      llvm::dyn_cast<clang::RecordDecl>(tag_decl);
+
+  if (record_decl != nullptr && (!record_decl->hasNameForLinkage() ||
+      record_decl->isAnonymousStructOrUnion())) {
+    return record_decl;
+  }
+  return nullptr;
+}
+
+bool RecordDeclWrapper::SetupRecordFields(abi_util::RecordTypeIR *recordp,
+                                          const std::string &source_file) {
   clang::RecordDecl::field_iterator field = record_decl_->field_begin();
+  uint32_t field_index = 0;
+  const clang::ASTRecordLayout &record_layout =
+      ast_contextp_->getASTRecordLayout(record_decl_);
   while (field != record_decl_->field_end()) {
-    abi_dump::RecordFieldDecl *record_fieldp = recordp->add_fields();
-    if (!record_fieldp) {
-      llvm::errs() << " Couldn't add record field: " << field->getName()
-                   << " to reference dump\n";
+    clang::QualType field_type = field->getType();
+    if (!CreateBasicNamedAndTypedDecl(field_type, source_file)) {
+      llvm::errs() << "Creation of Type failed\n";
       return false;
     }
-    if (!SetupBasicNamedAndTypedDecl(record_fieldp->mutable_basic_abi(),
-                                     field->getType(), field->getName(),
-                                     field->getAccess(), "", true)) {
+    std::string field_type_str = QualTypeToString(field_type);
+    std::string field_name = field->getName();
+    // Handle anoymous structs / unions as fields.
+    if (const clang::RecordDecl *anon_record_decl =
+        GetAnonymousRecord(field_type)) {
+      // We need to create a unique linker set key for anonymous structs / enums
+      // since clang just names them with fully_qualified_scope::anonymous.
+      field_type_str =
+          previous_record_stages_ + "::(anonymous)" +
+          std::to_string(field_index);
+      if (!CreateAnonymousRecord(anon_record_decl, field_type_str)) {
       return false;
+      }
+    } else if (const clang::EnumDecl *enum_decl =
+               GetAnonymousEnum(field_type)) {
+      // Handle anonymous enums.
+      field_type_str = QualTypeToString(enum_decl->getIntegerType());
     }
+    uint64_t field_offset = record_layout.getFieldOffset(field_index);
+    recordp->AddRecordField(abi_util::RecordFieldIR(
+        field_name, field_type_str, field_offset,
+        AccessClangToIR(field->getAccess())));
     field++;
+    field_index++;
   }
   return true;
 }
 
 bool RecordDeclWrapper::SetupCXXBases(
-    abi_dump::RecordDecl *cxxp,
-    const clang::CXXRecordDecl *cxx_record_decl) const {
-  assert(cxx_record_decl != nullptr);
+    abi_util::RecordTypeIR *cxxp,
+    const clang::CXXRecordDecl *cxx_record_decl) {
+  if (!cxx_record_decl || !cxxp) {
+    return false;
+  }
   clang::CXXRecordDecl::base_class_const_iterator base_class =
       cxx_record_decl->bases_begin();
   while (base_class != cxx_record_decl->bases_end()) {
-    abi_dump::CXXBaseSpecifier *base_specifierp = cxxp->add_base_specifiers();
-    if (!base_specifierp) {
-      llvm::errs() << " Couldn't add base specifier to reference dump\n";
-      return false;
-    }
     std::string name = QualTypeToString(base_class->getType());
     bool is_virtual = base_class->isVirtual();
-    if (!SetupBasicNamedAndTypedDecl(base_specifierp->mutable_basic_abi(),
-                                     base_class->getType(),
-                                     "", base_class->getAccessSpecifier(),
-                                     "", false)) {
-      return false;
-    }
-    base_specifierp->set_is_virtual(is_virtual);
+    abi_util::AccessSpecifierIR access =
+        AccessClangToIR(base_class->getAccessSpecifier());
+    cxxp->AddCXXBaseSpecifier(abi_util::CXXBaseSpecifierIR(name, is_virtual,
+                                                           access));
     base_class++;
   }
   return true;
 }
 
 bool RecordDeclWrapper::SetupRecordVTable(
-    abi_dump::RecordDecl *record_declp,
-    const clang::CXXRecordDecl *cxx_record_decl) const {
-  assert(cxx_record_decl != nullptr);
+    abi_util::RecordTypeIR *record_declp,
+    const clang::CXXRecordDecl *cxx_record_decl) {
+  if (!cxx_record_decl || !record_declp) {
+    return false;
+  }
   clang::VTableContextBase *base_vtable_contextp =
       ast_contextp_->getVTableContext();
   const clang::Type *typep = cxx_record_decl->getTypeForDecl();
@@ -386,263 +531,254 @@
   }
   const clang::VTableLayout &vtable_layout =
       itanium_vtable_contextp->getVTableLayout(cxx_record_decl);
-  abi_dump::VTableLayout *vtablep = record_declp->mutable_vtable_layout();
-  if (!vtablep) {
-    return false;
-  }
+  abi_util::VTableLayoutIR vtable_ir_layout;
   for (const auto &vtable_component : vtable_layout.vtable_components()) {
-    abi_dump::VTableComponent *added_vtable_component =
-        vtablep->add_vtable_components();
-    if (!added_vtable_component ||
-        !SetupRecordVTableComponent(added_vtable_component, vtable_component)) {
+    abi_util::VTableComponentIR added_component=
+        SetupRecordVTableComponent(vtable_component);
+    vtable_ir_layout.AddVTableComponent(std::move(added_component));
+  }
+  record_declp->SetVTableLayout(std::move(vtable_ir_layout));
+  return true;
+}
+
+abi_util::VTableComponentIR RecordDeclWrapper::SetupRecordVTableComponent(
+    const clang::VTableComponent &vtable_component) {
+  abi_util::VTableComponentIR::Kind kind =
+      abi_util::VTableComponentIR::Kind::RTTI;
+  std::string mangled_component_name = "";
+  llvm::raw_string_ostream ostream(mangled_component_name);
+  int64_t value = 0;
+  clang::VTableComponent::Kind clang_component_kind =
+      vtable_component.getKind();
+  switch (clang_component_kind) {
+    case clang::VTableComponent::CK_VCallOffset:
+      kind = abi_util::VTableComponentIR::Kind::VCallOffset;
+      value = vtable_component.getVCallOffset().getQuantity();
+      break;
+    case clang::VTableComponent::CK_VBaseOffset:
+      kind = abi_util::VTableComponentIR::Kind::VBaseOffset;
+      value = vtable_component.getVBaseOffset().getQuantity();
+      break;
+    case clang::VTableComponent::CK_OffsetToTop:
+      kind = abi_util::VTableComponentIR::Kind::OffsetToTop;
+      value = vtable_component.getOffsetToTop().getQuantity();
+      break;
+    case clang::VTableComponent::CK_RTTI:
+      {
+        kind = abi_util::VTableComponentIR::Kind::RTTI;
+        const clang::CXXRecordDecl *rtti_decl =
+            vtable_component.getRTTIDecl();
+        assert(rtti_decl != nullptr);
+        mangled_component_name =
+            ABIWrapper::GetTypeLinkageName(rtti_decl->getTypeForDecl());
+      }
+      break;
+    case clang::VTableComponent::CK_FunctionPointer:
+    case clang::VTableComponent::CK_CompleteDtorPointer:
+    case clang::VTableComponent::CK_DeletingDtorPointer:
+    case clang::VTableComponent::CK_UnusedFunctionPointer:
+      {
+        const clang::CXXMethodDecl *method_decl =
+            vtable_component.getFunctionDecl();
+        assert(method_decl != nullptr);
+        switch (clang_component_kind) {
+          case clang::VTableComponent::CK_FunctionPointer:
+            kind = abi_util::VTableComponentIR::Kind::FunctionPointer;
+            mangled_component_name = GetMangledNameDecl(method_decl,
+                                                        mangle_contextp_);
+              break;
+          case clang::VTableComponent::CK_CompleteDtorPointer:
+            kind = abi_util::VTableComponentIR::Kind::CompleteDtorPointer;
+            mangle_contextp_->mangleCXXDtor(
+                vtable_component.getDestructorDecl(),
+                clang::CXXDtorType::Dtor_Complete, ostream);
+            ostream.flush();
+            break;
+          case clang::VTableComponent::CK_DeletingDtorPointer:
+            kind = abi_util::VTableComponentIR::Kind::DeletingDtorPointer;
+            mangle_contextp_->mangleCXXDtor(
+                vtable_component.getDestructorDecl(),
+                clang::CXXDtorType::Dtor_Deleting, ostream);
+            ostream.flush();
+            break;
+          case clang::VTableComponent::CK_UnusedFunctionPointer:
+            kind = abi_util::VTableComponentIR::Kind::UnusedFunctionPointer;
+            break;
+          default:
+            break;
+        }
+      }
+      break;
+    default:
+      break;
+  }
+  return abi_util::VTableComponentIR(mangled_component_name, kind, value);
+}
+
+bool RecordDeclWrapper::SetupTemplateInfo(
+    abi_util::RecordTypeIR *record_declp,
+    const clang::CXXRecordDecl *cxx_record_decl,
+    const std::string &source_file) {
+  assert(cxx_record_decl != nullptr);
+  const clang::ClassTemplateSpecializationDecl *specialization_decl =
+      clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(cxx_record_decl);
+  if (specialization_decl) {
+    const clang::TemplateArgumentList *arg_list =
+        &specialization_decl->getTemplateArgs();
+    if (arg_list &&
+        !SetupTemplateArguments(arg_list, record_declp, source_file)) {
       return false;
     }
   }
   return true;
 }
 
-bool RecordDeclWrapper::SetupRecordVTableComponent(
-    abi_dump::VTableComponent *added_vtable_component,
-    const clang::VTableComponent &vtable_component) const {
-  assert(added_vtable_component != nullptr);
-  abi_dump::VTableComponent_Kind kind = abi_dump::VTableComponent_Kind_RTTI;
-  std::string mangled_component_name = "";
-  llvm::raw_string_ostream ostream(mangled_component_name);
-  int64_t value = 0;
-  clang::VTableComponent::Kind clang_component_kind =
-      vtable_component.getKind();
-    switch (clang_component_kind) {
-      case clang::VTableComponent::CK_VCallOffset:
-        kind =  abi_dump::VTableComponent_Kind_VCallOffset;
-        value = vtable_component.getVCallOffset().getQuantity();
-        break;
-      case clang::VTableComponent::CK_VBaseOffset:
-        kind =  abi_dump::VTableComponent_Kind_VBaseOffset;
-        value = vtable_component.getVBaseOffset().getQuantity();
-        break;
-      case clang::VTableComponent::CK_OffsetToTop:
-        kind =  abi_dump::VTableComponent_Kind_OffsetToTop;
-        value = vtable_component.getOffsetToTop().getQuantity();
-        break;
-      case clang::VTableComponent::CK_RTTI:
-        {
-          kind =  abi_dump::VTableComponent_Kind_RTTI;
-          const clang::CXXRecordDecl *rtti_decl =
-              vtable_component.getRTTIDecl();
-          assert(rtti_decl != nullptr);
-          mangled_component_name =
-              ABIWrapper::GetTypeLinkageName(rtti_decl->getTypeForDecl());
-        }
-        break;
-      case clang::VTableComponent::CK_FunctionPointer:
-      case clang::VTableComponent::CK_CompleteDtorPointer:
-      case clang::VTableComponent::CK_DeletingDtorPointer:
-      case clang::VTableComponent::CK_UnusedFunctionPointer:
-        {
-          const clang::CXXMethodDecl *method_decl =
-              vtable_component.getFunctionDecl();
-          assert(method_decl != nullptr);
-          switch (clang_component_kind) {
-            case clang::VTableComponent::CK_FunctionPointer:
-              kind =  abi_dump::VTableComponent_Kind_FunctionPointer;
-              mangled_component_name = GetMangledNameDecl(method_decl,
-                                                          mangle_contextp_);
-              break;
-            case clang::VTableComponent::CK_CompleteDtorPointer:
-              kind =  abi_dump::VTableComponent_Kind_CompleteDtorPointer;
-              mangle_contextp_->mangleCXXDtor(
-                  vtable_component.getDestructorDecl(),
-                  clang::CXXDtorType::Dtor_Complete, ostream);
-              ostream.flush();
-
-              break;
-            case clang::VTableComponent::CK_DeletingDtorPointer:
-              kind =  abi_dump::VTableComponent_Kind_DeletingDtorPointer;
-              mangle_contextp_->mangleCXXDtor(
-                  vtable_component.getDestructorDecl(),
-                  clang::CXXDtorType::Dtor_Deleting, ostream);
-              ostream.flush();
-              break;
-            case clang::VTableComponent::CK_UnusedFunctionPointer:
-              kind =  abi_dump::VTableComponent_Kind_UnusedFunctionPointer;
-            default:
-              break;
-          }
-        }
-        break;
-      default:
-        return false;
-    }
-  added_vtable_component->set_kind(kind);
-  added_vtable_component->set_component_value(value);
-  added_vtable_component->set_mangled_component_name(mangled_component_name);
-  return true;
-}
-
-bool RecordDeclWrapper::SetupTemplateInfo(
-    abi_dump::RecordDecl *record_declp,
-    const clang::CXXRecordDecl *cxx_record_decl) const {
-  assert(cxx_record_decl != nullptr);
-  if (cxx_record_decl->isTemplateDecl()) {
-    clang::ClassTemplateDecl *template_decl =
-        cxx_record_decl->getDescribedClassTemplate();
-    if (template_decl) {
-      clang::TemplateParameterList *template_parameter_list =
-          template_decl->getTemplateParameters();
-      if (template_parameter_list &&
-          !SetupTemplateParamNames(record_declp->mutable_template_info(),
-                                   template_parameter_list)) {
-        return false;
-      }
-    }
-  } else {
-    const clang::ClassTemplateSpecializationDecl *specialization_decl =
-        clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
-            cxx_record_decl);
-    if(specialization_decl) {
-      const clang::TemplateArgumentList *arg_list =
-          &specialization_decl->getTemplateArgs();
-      if (arg_list &&
-          !SetupTemplateArguments(record_declp->mutable_template_info(),
-                                  arg_list)) {
-        return false;
-      }
-    }
+bool RecordDeclWrapper::SetupRecordInfo(abi_util::RecordTypeIR *record_declp,
+                                        const std::string &source_file) {
+  if (!record_declp) {
+    return false;
   }
-  return true;
-}
 
-bool RecordDeclWrapper::SetupRecordInfo(abi_dump::RecordDecl *record_declp,
-                                        const std::string &source_file) const {
-  std::string qualified_name = GetTagDeclQualifiedName(record_decl_);
+  if (record_decl_->isStruct()) {
+    record_declp->SetRecordKind(
+        abi_util::RecordTypeIR::RecordKind::struct_kind);
+  } else if (record_decl_->isClass()) {
+    record_declp->SetRecordKind(
+        abi_util::RecordTypeIR::RecordKind::class_kind);
+  } else {
+    record_declp->SetRecordKind(
+        abi_util::RecordTypeIR::RecordKind::union_kind);
+  }
+
   const clang::Type *basic_type = nullptr;
   if (!(basic_type = record_decl_->getTypeForDecl())) {
     return false;
   }
-  std::string mangled_name = ABIWrapper::GetTypeLinkageName(basic_type);
-  clang::QualType type = basic_type->getCanonicalTypeInternal();
-  std::string linker_key = (mangled_name == "") ? qualified_name : mangled_name;
-  if (!SetupBasicNamedAndTypedDecl(record_declp->mutable_basic_abi(),
-                                   type, qualified_name,
-                                   record_decl_->getAccess(), linker_key,
-                                   true)) {
+  clang::QualType qual_type = basic_type->getCanonicalTypeInternal();
+  if (!CreateExtendedType(qual_type, record_declp)) {
     return false;
   }
-  record_declp->set_mangled_record_name(mangled_name);
-  record_declp->set_source_file(source_file);
-  return true;
+  std::string record_qual_type_str = QualTypeToString(qual_type);
+  record_declp->SetSourceFile(source_file);
+  if (!record_decl_->hasNameForLinkage() ||
+      record_decl_->isAnonymousStructOrUnion()) {
+    record_declp->SetLinkerSetKey(previous_record_stages_);
+    record_declp->SetAnonymity(true);
+  } else {
+    previous_record_stages_ = record_qual_type_str;
+    record_declp->SetLinkerSetKey(record_qual_type_str);
+  }
+  record_declp->SetAccess(AccessClangToIR(record_decl_->getAccess()));
+  return SetupRecordFields(record_declp, source_file) &&
+      SetupCXXRecordInfo(record_declp, source_file);
 }
 
 bool RecordDeclWrapper::SetupCXXRecordInfo(
-    abi_dump::RecordDecl *record_declp) const {
+    abi_util::RecordTypeIR *record_declp, const std::string &source_file) {
   const clang::CXXRecordDecl *cxx_record_decl =
       clang::dyn_cast<clang::CXXRecordDecl>(record_decl_);
   if (!cxx_record_decl) {
     return true;
   }
-  return SetupTemplateInfo(record_declp, cxx_record_decl) &&
+  return SetupTemplateInfo(record_declp, cxx_record_decl, source_file) &&
       SetupCXXBases(record_declp, cxx_record_decl) &&
       SetupRecordVTable(record_declp, cxx_record_decl);
 }
 
-std::unique_ptr<abi_dump::RecordDecl> RecordDeclWrapper::GetRecordDecl() const {
-  std::unique_ptr<abi_dump::RecordDecl> abi_decl(new abi_dump::RecordDecl());
-  std::string source_file = GetDeclSourceFile(record_decl_, cip_);
-  abi_dump::RecordDecl *record_declp = abi_decl.get();
-  if (!SetupRecordInfo(record_declp, source_file) ||
-      !SetupRecordFields(record_declp) ||
-      !SetupCXXRecordInfo(abi_decl.get())) {
+bool RecordDeclWrapper::GetRecordDecl() {
+  auto abi_decl = std::make_unique<abi_util::RecordTypeIR>();
+  std::string source_file = GetCachedDeclSourceFile(record_decl_, cip_);
+  if (!SetupRecordInfo(abi_decl.get(), source_file)) {
     llvm::errs() << "Setting up CXX Bases / Template Info failed\n";
-    return nullptr;
+    return false;
   }
-  return abi_decl;
+  return ir_dumper_->AddLinkableMessageIR(abi_decl.get());
 }
 
 EnumDeclWrapper::EnumDeclWrapper(
     clang::MangleContext *mangle_contextp,
     clang::ASTContext *ast_contextp,
     const clang::CompilerInstance *compiler_instance_p,
-    const clang::EnumDecl *decl)
-  : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
+    const clang::EnumDecl *decl,
+    std::set<std::string> *type_cache,
+    abi_util::IRDumper *ir_dumper,
+    std::map<const clang::Decl *, std::string> &decl_to_source_cache)
+  : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p,
+               type_cache, ir_dumper, decl_to_source_cache),
     enum_decl_(decl) { }
 
-bool EnumDeclWrapper::SetupEnumFields(abi_dump::EnumDecl *enump) const {
+bool EnumDeclWrapper::SetupEnumFields(abi_util::EnumTypeIR *enump) {
+  if (!enump) {
+    return false;
+  }
   clang::EnumDecl::enumerator_iterator enum_it = enum_decl_->enumerator_begin();
   while (enum_it != enum_decl_->enumerator_end()) {
-    abi_dump::EnumFieldDecl *enum_fieldp = enump->add_enum_fields();
     std::string name = enum_it->getQualifiedNameAsString();
     uint64_t field_value = enum_it->getInitVal().getExtValue();
-    if (!enum_fieldp ||
-        !SetupBasicNamedAndTypedDecl(enum_fieldp->mutable_basic_abi(),
-                                     enum_it->getType(), name,
-                                     enum_it->getAccess(),
-                                     std::to_string(field_value), true)) {
-      return false;
-    }
-    enum_fieldp->set_enum_field_value(field_value);
+    enump->AddEnumField(abi_util::EnumFieldIR(name, field_value));
     enum_it++;
   }
   return true;
 }
 
-bool EnumDeclWrapper::SetupEnum(abi_dump::EnumDecl *enump,
-                                const std::string &source_file) const {
+bool EnumDeclWrapper::SetupEnum(abi_util::EnumTypeIR *enum_type,
+                                const std::string &source_file) {
   std::string enum_name = GetTagDeclQualifiedName(enum_decl_);
-  clang::QualType enum_type = enum_decl_->getIntegerType();
-  if (!SetupBasicNamedAndTypedDecl(enump->mutable_basic_abi(), enum_type,
-                                   enum_name, enum_decl_->getAccess(),
-                                   enum_name, true) ||
-      !SetupEnumFields(enump)) {
+  clang::QualType enum_qual_type =
+      enum_decl_->getTypeForDecl()->getCanonicalTypeInternal();
+  if (!CreateExtendedType(enum_qual_type, enum_type)) {
     return false;
   }
-  enump->set_source_file(source_file);
-  return true;
+  enum_type->SetSourceFile(source_file);
+  enum_type->SetUnderlyingType(QualTypeToString(enum_decl_->getIntegerType()));
+  enum_type->SetAccess(AccessClangToIR(enum_decl_->getAccess()));
+  return SetupEnumFields(enum_type) &&
+      CreateBasicNamedAndTypedDecl(enum_decl_->getIntegerType(), "");
 }
 
-std::unique_ptr<abi_dump::EnumDecl> EnumDeclWrapper::GetEnumDecl() const {
-  std::unique_ptr<abi_dump::EnumDecl> abi_decl(new abi_dump::EnumDecl());
-  std::string source_file = GetDeclSourceFile(enum_decl_, cip_);
+bool EnumDeclWrapper::GetEnumDecl() {
+  auto abi_decl = std::make_unique<abi_util::EnumTypeIR>();
+  std::string source_file = GetCachedDeclSourceFile(enum_decl_, cip_);
 
   if (!SetupEnum(abi_decl.get(), source_file)) {
-    llvm::errs() << "Setting up Enum fields failed\n";
-    return nullptr;
+    llvm::errs() << "Setting up Enum failed\n";
+    return false;
   }
-  return abi_decl;
+  return ir_dumper_->AddLinkableMessageIR(abi_decl.get());
 }
 
 GlobalVarDeclWrapper::GlobalVarDeclWrapper(
     clang::MangleContext *mangle_contextp,
     clang::ASTContext *ast_contextp,
     const clang::CompilerInstance *compiler_instance_p,
-    const clang::VarDecl *decl)
-  : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p),
+    const clang::VarDecl *decl,std::set<std::string> *type_cache,
+    abi_util::IRDumper *ir_dumper,
+    std::map<const clang::Decl *, std::string> &decl_to_source_cache)
+  : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p, type_cache,
+               ir_dumper, decl_to_source_cache),
     global_var_decl_(decl) { }
 
 bool GlobalVarDeclWrapper::SetupGlobalVar(
-    abi_dump::GlobalVarDecl *global_varp,
-    const std::string &source_file) const {
+    abi_util::GlobalVarIR *global_varp,
+    const std::string &source_file) {
   // Temporary fix : clang segfaults on trying to mangle global variable which
   // is a dependent sized array type.
-  std::string qualified_name = global_var_decl_->getQualifiedNameAsString();
   std::string mangled_name =
       GetMangledNameDecl(global_var_decl_, mangle_contextp_);
-  if (!SetupBasicNamedAndTypedDecl(
-      global_varp->mutable_basic_abi(),global_var_decl_->getType(),
-      qualified_name, global_var_decl_->getAccess(),
-      mangled_name, true)) {
+  if (!CreateBasicNamedAndTypedDecl(global_var_decl_->getType(), source_file)) {
     return false;
   }
-  global_varp->set_source_file(source_file);
+  global_varp->SetSourceFile(source_file);
+  global_varp->SetName(global_var_decl_->getQualifiedNameAsString());
+  global_varp->SetLinkerSetKey(mangled_name);
+  global_varp->SetReferencedType(
+      QualTypeToString(global_var_decl_->getType()));
   return true;
 }
 
-std::unique_ptr<abi_dump::GlobalVarDecl>
-GlobalVarDeclWrapper::GetGlobalVarDecl() const {
-  std::unique_ptr<abi_dump::GlobalVarDecl>
-      abi_decl(new abi_dump::GlobalVarDecl);
-  std::string source_file = GetDeclSourceFile(global_var_decl_, cip_);
-  if (!SetupGlobalVar(abi_decl.get(), source_file)) {
-    return nullptr;
-  }
-  return abi_decl;
+bool GlobalVarDeclWrapper::GetGlobalVarDecl() {
+  auto abi_decl = std::make_unique<abi_util::GlobalVarIR>();
+  std::string source_file = GetCachedDeclSourceFile(global_var_decl_, cip_);
+  return SetupGlobalVar(abi_decl.get(), source_file) &&
+      ir_dumper_->AddLinkableMessageIR(abi_decl.get());
 }
diff --git a/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.h b/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.h
index 262c9cf..af222b0 100644
--- a/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.h
+++ b/vndk/tools/header-checker/header-abi-dumper/src/abi_wrappers.h
@@ -15,6 +15,8 @@
 #ifndef ABI_WRAPPERS_H_
 #define ABI_WRAPPERS_H_
 
+#include <ir_representation.h>
+
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunused-parameter"
 #pragma clang diagnostic ignored "-Wnested-anon-types"
@@ -32,7 +34,10 @@
  public:
   ABIWrapper(clang::MangleContext *mangle_contextp,
              clang::ASTContext *ast_contextp,
-             const clang::CompilerInstance *cip);
+             const clang::CompilerInstance *cip,
+             std::set<std::string> *type_cache,
+             abi_util::IRDumper *ir_dumper,
+             std::map<const clang::Decl *, std::string> &decl_to_source_cache);
 
   static std::string GetDeclSourceFile(const clang::Decl *decl,
                                        const clang::CompilerInstance *cip);
@@ -41,123 +46,161 @@
                                         clang::MangleContext *mangle_context);
  protected:
   abi_dump::AccessSpecifier AccessClangToDump(
-      const clang::AccessSpecifier sp) const;
+      const clang::AccessSpecifier sp);
+  std::string GetCachedDeclSourceFile(const clang::Decl *decl,
+                                      const clang::CompilerInstance *cip);
 
-  bool SetupTemplateParamNames(abi_dump::TemplateInfo *tinfo,
-                               clang::TemplateParameterList *pl) const;
+  bool SetupTemplateArguments(const clang::TemplateArgumentList *tl,
+                              abi_util::TemplatedArtifactIR *ta,
+                              const std::string &source_file);
 
-  bool SetupTemplateArguments(abi_dump::TemplateInfo *tinfo,
-                              const clang::TemplateArgumentList *tl) const;
+  std::string QualTypeToString(const clang::QualType &sweet_qt);
 
-  std::string QualTypeToString(const clang::QualType &sweet_qt) const;
+  std::string GetTagDeclQualifiedName(const clang::TagDecl *decl);
 
-  std::string GetTagDeclQualifiedName(const clang::TagDecl *decl) const;
+  bool CreateBasicNamedAndTypedDecl(clang::QualType,
+                                    const std::string &source_file);
+  bool CreateBasicNamedAndTypedDecl(
+      clang::QualType canonical_type,
+      abi_util::TypeIR *typep,
+      const std::string &source_file);
 
-  bool SetupBasicTypeAbi(abi_dump::BasicTypeAbi *type_abi,
-                         const clang::QualType type, bool dump_size) const;
+  bool CreateExtendedType(
+      clang::QualType canonical_type,
+      abi_util::TypeIR *typep);
 
-  bool SetupBasicNamedAndTypedDecl(
-      abi_dump::BasicNamedAndTypedDecl *basic_named_and_typed_decl,
-      const clang::QualType type, const std::string &name,
-      const clang::AccessSpecifier &access, std::string key,
-      bool dump_size) const;
+  clang::QualType GetReferencedType(const clang::QualType qual_type);
 
-  std::string GetTypeLinkageName(const clang::Type *typep) const;
+  std::string GetTypeLinkageName(const clang::Type *typep);
 
-protected:
+  std::unique_ptr<abi_util::TypeIR> SetTypeKind(const clang::QualType qtype,
+                                                const std::string &source_file);
+
+
+ protected:
   const clang::CompilerInstance *cip_;
   clang::MangleContext *mangle_contextp_;
   clang::ASTContext *ast_contextp_;
+  std::set<std::string> *type_cache_;
+  abi_util::IRDumper *ir_dumper_;
+  std::map<const clang::Decl *, std::string> &decl_to_source_file_cache_;
 };
 
 class RecordDeclWrapper : public ABIWrapper {
  public:
-  RecordDeclWrapper(clang::MangleContext *mangle_contextp,
-                    clang::ASTContext *ast_contextp,
-                    const clang::CompilerInstance *compiler_instance_p,
-                    const clang::RecordDecl *decl);
+  RecordDeclWrapper(
+      clang::MangleContext *mangle_contextp, clang::ASTContext *ast_contextp,
+      const clang::CompilerInstance *compiler_instance_p,
+      const clang::RecordDecl *decl, std::set<std::string> *type_cache,
+      abi_util::IRDumper *ir_dumper,
+      std::map<const clang::Decl *, std::string> &decl_to_source_cache_,
+      const std::string &previous_record_stages);
 
-  std::unique_ptr<abi_dump::RecordDecl> GetRecordDecl() const;
+  bool GetRecordDecl();
 
  private:
   const clang::RecordDecl *record_decl_;
+  std::string previous_record_stages_;
 
  private:
-  bool SetupRecordInfo(abi_dump::RecordDecl *record_declp,
-                       const std::string &source_file) const;
+  bool SetupRecordInfo(abi_util::RecordTypeIR *type,
+                       const std::string &source_file);
 
-  bool SetupRecordFields(abi_dump::RecordDecl *record_declp) const;
+  bool SetupRecordFields(abi_util::RecordTypeIR *record_declp,
+                         const std::string &source_file);
 
-  bool SetupCXXBases(abi_dump::RecordDecl *cxxp,
-                     const clang::CXXRecordDecl *cxx_record_decl) const;
+  bool SetupCXXBases(abi_util::RecordTypeIR *cxxp,
+                     const clang::CXXRecordDecl *cxx_record_decl);
 
-  bool SetupTemplateInfo(abi_dump::RecordDecl *record_declp,
-                         const clang::CXXRecordDecl *cxx_record_decl) const;
+  bool SetupTemplateInfo(abi_util::RecordTypeIR *record_declp,
+                         const clang::CXXRecordDecl *cxx_record_decl,
+                         const std::string &source_file);
 
-  bool SetupRecordVTable(abi_dump::RecordDecl *record_declp,
-                         const clang::CXXRecordDecl *cxx_record_decl) const;
-  bool SetupRecordVTableComponent(
-      abi_dump::VTableComponent *added_vtable_component,
-      const clang::VTableComponent &vtable_component) const;
+  bool SetupRecordVTable(abi_util::RecordTypeIR *record_declp,
+                         const clang::CXXRecordDecl *cxx_record_decl);
+  abi_util::VTableComponentIR SetupRecordVTableComponent(
+      const clang::VTableComponent &vtable_component);
 
-  bool SetupCXXRecordInfo(abi_dump::RecordDecl *record_declp) const;
+  bool SetupCXXRecordInfo(abi_util::RecordTypeIR *record_declp,
+                          const std::string &source_file);
+
+  bool CreateAnonymousRecord(
+      const clang::RecordDecl *decl, const std::string &linker_set_key);
 };
 
 class FunctionDeclWrapper : public ABIWrapper {
  public:
-  FunctionDeclWrapper(clang::MangleContext *mangle_contextp,
-                      clang::ASTContext *ast_contextp,
-                      const clang::CompilerInstance *compiler_instance_p,
-                      const clang::FunctionDecl *decl);
+  FunctionDeclWrapper(
+      clang::MangleContext *mangle_contextp, clang::ASTContext *ast_contextp,
+      const clang::CompilerInstance *compiler_instance_p,
+      const clang::FunctionDecl *decl, std::set<std::string> *type_cache,
+      abi_util::IRDumper *ir_dumper,
+      std::map<const clang::Decl *, std::string> &decl_to_source_cache_);
 
-  std::unique_ptr<abi_dump::FunctionDecl> GetFunctionDecl() const;
+  std::unique_ptr<abi_util::FunctionIR> GetFunctionDecl();
 
  private:
   const clang::FunctionDecl *function_decl_;
 
  private:
-  bool SetupFunction(abi_dump::FunctionDecl *methodp,
-                     const std::string &source_file) const;
+  bool SetupFunction(abi_util::FunctionIR *methodp,
+                     const std::string &source_file);
 
-  bool SetupTemplateInfo(abi_dump::FunctionDecl *functionp) const;
+  bool SetupTemplateInfo(abi_util::FunctionIR *functionp,
+                         const std::string &source_file);
 
-  bool SetupFunctionParameters(abi_dump::FunctionDecl *functionp) const;
+  bool SetupFunctionParameters(abi_util::FunctionIR *functionp,
+                               const std::string &source_file);
+
+  bool SetupFunctionParameter(abi_util::FunctionIR *functionp,
+                              const clang::QualType qual_type,
+                              bool has_default_arg,
+                              const std::string &source_file);
+
+  bool SetupThisParameter(abi_util::FunctionIR *functionp,
+                          const std::string &source_file);
+
 };
 
 class EnumDeclWrapper : public ABIWrapper {
  public:
-  EnumDeclWrapper(clang::MangleContext *mangle_contextp,
-                  clang::ASTContext *ast_contextp,
-                  const clang::CompilerInstance *compiler_instance_p,
-                  const clang::EnumDecl *decl);
+  EnumDeclWrapper(
+      clang::MangleContext *mangle_contextp, clang::ASTContext *ast_contextp,
+      const clang::CompilerInstance *compiler_instance_p,
+      const clang::EnumDecl *decl,
+      std::set<std::string> *type_cache, abi_util::IRDumper *ir_dumper,
+      std::map<const clang::Decl *, std::string> &decl_to_source_cache_);
 
-  std::unique_ptr<abi_dump::EnumDecl> GetEnumDecl() const;
+  bool GetEnumDecl();
 
  private:
   const clang::EnumDecl *enum_decl_;
 
  private:
-  bool SetupEnum(abi_dump::EnumDecl *enump,
-                 const std::string &source_file) const;
-  bool SetupEnumFields(abi_dump::EnumDecl *enump) const;
+  bool SetupEnum(abi_util::EnumTypeIR *type,
+                 const std::string &source_file);
+
+  bool SetupEnumFields(abi_util::EnumTypeIR *enump);
 };
 
 class GlobalVarDeclWrapper : public ABIWrapper {
  public:
-  GlobalVarDeclWrapper(clang::MangleContext *mangle_contextp,
-                  clang::ASTContext *ast_contextp,
-                  const clang::CompilerInstance *compiler_instance_p,
-                  const clang::VarDecl *decl);
+  GlobalVarDeclWrapper(
+      clang::MangleContext *mangle_contextp, clang::ASTContext *ast_contextp,
+      const clang::CompilerInstance *compiler_instance_p,
+      const clang::VarDecl *decl,
+      std::set<std::string> *type_cache, abi_util::IRDumper *ir_dumper,
+      std::map<const clang::Decl *, std::string> &decl_to_source_cache_);
 
-  std::unique_ptr<abi_dump::GlobalVarDecl> GetGlobalVarDecl() const;
+  bool GetGlobalVarDecl();
 
  private:
   const clang::VarDecl *global_var_decl_;
  private:
-  bool SetupGlobalVar(abi_dump::GlobalVarDecl *global_varp,
-                      const std::string &source_file) const;
+  bool SetupGlobalVar(abi_util::GlobalVarIR *global_varp,
+                      const std::string &source_file);
 };
 
 } //end namespace abi_wrapper
 
-#endif  // ABI_WRAPPERS_H_
+#endif // ABI_WRAPPERS_H_
diff --git a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp
index 66b3e9d..abf58ed 100644
--- a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp
+++ b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.cpp
@@ -19,9 +19,6 @@
 #include <clang/Tooling/Core/QualTypeNames.h>
 #include <clang/Index/CodegenNameGenerator.h>
 
-#include <google/protobuf/text_format.h>
-#include <google/protobuf/io/zero_copy_stream_impl.h>
-
 #include <fstream>
 #include <iostream>
 #include <string>
@@ -33,83 +30,64 @@
 using abi_wrapper::GlobalVarDeclWrapper;
 
 HeaderASTVisitor::HeaderASTVisitor(
-    abi_dump::TranslationUnit *tu_ptr,
     clang::MangleContext *mangle_contextp,
     clang::ASTContext *ast_contextp,
     const clang::CompilerInstance *compiler_instance_p,
     const std::string &current_file_name,
     const std::set<std::string> &exported_headers,
-    const clang::Decl *tu_decl)
-  : tu_ptr_(tu_ptr),
-    mangle_contextp_(mangle_contextp),
+    const clang::Decl *tu_decl,
+    std::set<std::string> *type_cache,
+    abi_util::IRDumper *ir_dumper)
+  : mangle_contextp_(mangle_contextp),
     ast_contextp_(ast_contextp),
     cip_(compiler_instance_p),
     current_file_name_(current_file_name),
     exported_headers_(exported_headers),
-    tu_decl_(tu_decl) { }
+    tu_decl_(tu_decl),
+    type_cache_(type_cache),
+    ir_dumper_(ir_dumper) { }
 
 bool HeaderASTVisitor::VisitRecordDecl(const clang::RecordDecl *decl) {
-  // Skip forward declaration.
+  // Skip forward declarations, dependent records. Also skip anonymous records
+  // as they will be traversed through record fields.
   if (!decl->isThisDeclarationADefinition() ||
-      decl->getTypeForDecl()->isDependentType()) {
+      decl->getTypeForDecl()->isDependentType() ||
+      decl->isAnonymousStructOrUnion() ||
+      !decl->hasNameForLinkage()) {
     return true;
   }
   RecordDeclWrapper record_decl_wrapper(
-      mangle_contextp_, ast_contextp_, cip_, decl);
-  std::unique_ptr<abi_dump::RecordDecl> wrapped_record_decl =
-      record_decl_wrapper.GetRecordDecl();
-  if (!wrapped_record_decl) {
-    llvm::errs() << "Getting Record Decl failed\n";
-    return false;
-  }
-  abi_dump::RecordDecl *added_record_declp = tu_ptr_->add_records();
-  if (!added_record_declp) {
-    return false;
-  }
-  *added_record_declp = *wrapped_record_decl;
-  return true;
+      mangle_contextp_, ast_contextp_, cip_, decl, type_cache_,
+      ir_dumper_, decl_to_source_file_cache_, "");
+  return record_decl_wrapper.GetRecordDecl();
 }
 
 bool HeaderASTVisitor::VisitEnumDecl(const clang::EnumDecl *decl) {
   if (!decl->isThisDeclarationADefinition() ||
-      decl->getTypeForDecl()->isDependentType()) {
+      decl->getTypeForDecl()->isDependentType() ||
+      !decl->hasNameForLinkage()) {
     return true;
   }
   EnumDeclWrapper enum_decl_wrapper(
-      mangle_contextp_, ast_contextp_, cip_, decl);
-  std::unique_ptr<abi_dump::EnumDecl> wrapped_enum_decl =
-      enum_decl_wrapper.GetEnumDecl();
-  if (!wrapped_enum_decl) {
-    llvm::errs() << "Getting Enum Decl failed\n";
-    return false;
-  }
-  abi_dump::EnumDecl *added_enum_declp = tu_ptr_->add_enums();
-  if (!added_enum_declp) {
-    return false;
-  }
-  *added_enum_declp = *wrapped_enum_decl;
-  return true;
-}
+      mangle_contextp_, ast_contextp_, cip_, decl, type_cache_,
+      ir_dumper_, decl_to_source_file_cache_);
+  return enum_decl_wrapper.GetEnumDecl();
+ }
 
-static bool MutateFunctionWithLinkageName(abi_dump::TranslationUnit *tu_ptr,
-                                          const abi_dump::FunctionDecl *fd,
+static bool MutateFunctionWithLinkageName(const abi_util::FunctionIR *function,
+                                          abi_util::IRDumper *ir_dumper,
                                           std::string &linkage_name) {
-  abi_dump::FunctionDecl *added_function_declp = tu_ptr->add_functions();
-  if (!added_function_declp) {
-    return false;
-  }
-  *added_function_declp = *fd;
-  added_function_declp->set_mangled_function_name(linkage_name);
-  assert(added_function_declp->mutable_basic_abi() != nullptr);
-  added_function_declp->mutable_basic_abi()->set_linker_set_key(linkage_name);
-  return true;
+  auto added_function = std::make_unique<abi_util::FunctionIR>();
+  *added_function = *function;
+  added_function->SetLinkerSetKey(linkage_name);
+  return ir_dumper->AddLinkableMessageIR(added_function.get());
 }
 
-static bool AddMangledFunctions(abi_dump::TranslationUnit *tu_ptr,
-                                const abi_dump::FunctionDecl *fd,
+static bool AddMangledFunctions(const abi_util::FunctionIR *function,
+                                abi_util:: IRDumper *ir_dumper,
                                 std::vector<std::string> &manglings) {
   for (auto &&mangling : manglings) {
-    if (!MutateFunctionWithLinkageName(tu_ptr, fd, mangling)) {
+    if (!MutateFunctionWithLinkageName(function, ir_dumper, mangling)) {
       return false;
     }
   }
@@ -139,23 +117,20 @@
     return true;
   }
   FunctionDeclWrapper function_decl_wrapper(mangle_contextp_, ast_contextp_,
-                                            cip_, decl);
-  std::unique_ptr<abi_dump::FunctionDecl> wrapped_function_decl =
-      function_decl_wrapper.GetFunctionDecl();
-  if (!wrapped_function_decl) {
-    llvm::errs() << "Getting Function Decl failed\n";
-    return false;
-  }
+                                            cip_, decl, type_cache_,
+                                            ir_dumper_,
+                                            decl_to_source_file_cache_);
+  auto function_wrapper = function_decl_wrapper.GetFunctionDecl();
   // Destructors and Constructors can have more than 1 symbol generated from the
   // same Decl.
   clang::index::CodegenNameGenerator cg(*ast_contextp_);
   std::vector<std::string> manglings = cg.getAllManglings(decl);
   if (!manglings.empty()) {
-    return AddMangledFunctions(tu_ptr_, wrapped_function_decl.get(), manglings);
+    return AddMangledFunctions(function_wrapper.get(), ir_dumper_, manglings);
   }
   std::string linkage_name =
       ABIWrapper::GetMangledNameDecl(decl, mangle_contextp_);
-  return MutateFunctionWithLinkageName(tu_ptr_, wrapped_function_decl.get(),
+  return MutateFunctionWithLinkageName(function_wrapper.get(), ir_dumper_,
                                        linkage_name);
 }
 
@@ -166,19 +141,10 @@
     return true;
   }
   GlobalVarDeclWrapper global_var_decl_wrapper(mangle_contextp_, ast_contextp_,
-                                               cip_, decl);
-  std::unique_ptr<abi_dump::GlobalVarDecl> wrapped_global_var_decl =
-      global_var_decl_wrapper.GetGlobalVarDecl();
-  if (!wrapped_global_var_decl) {
-    llvm::errs() << "Getting Global Var Decl failed\n";
-    return false;
-  }
-  abi_dump::GlobalVarDecl *added_global_var_declp = tu_ptr_->add_global_vars();
-  if (!added_global_var_declp) {
-    return false;
-  }
-  *added_global_var_declp = *wrapped_global_var_decl;
-  return true;
+                                               cip_, decl, type_cache_,
+                                               ir_dumper_,
+                                               decl_to_source_file_cache_);
+  return  global_var_decl_wrapper.GetGlobalVarDecl();
 }
 
 static bool AreHeadersExported(const std::set<std::string> &exported_headers) {
@@ -191,6 +157,7 @@
     return true;
   }
   std::string source_file = ABIWrapper::GetDeclSourceFile(decl, cip_);
+  decl_to_source_file_cache_.insert(std::make_pair(decl, source_file));
   // If no exported headers are specified we assume the whole AST is exported.
   if ((decl != tu_decl_) && AreHeadersExported(exported_headers_) &&
       (exported_headers_.find(source_file) == exported_headers_.end())) {
@@ -210,18 +177,19 @@
     exported_headers_(exported_headers) { }
 
 void HeaderASTConsumer::HandleTranslationUnit(clang::ASTContext &ctx) {
-  GOOGLE_PROTOBUF_VERIFY_VERSION;
-  std::ofstream text_output(out_dump_name_);
-  google::protobuf::io::OstreamOutputStream text_os(&text_output);
+  clang::PrintingPolicy policy(ctx.getPrintingPolicy());
+  policy.SuppressTagKeyword = true;
+  ctx.setPrintingPolicy(policy);
   clang::TranslationUnitDecl *translation_unit = ctx.getTranslationUnitDecl();
   std::unique_ptr<clang::MangleContext> mangle_contextp(
       ctx.createMangleContext());
-  abi_dump::TranslationUnit tu;
-  std::string str_out;
-  HeaderASTVisitor v(&tu, mangle_contextp.get(), &ctx, cip_, file_name_,
-                     exported_headers_, translation_unit);
-  if (!v.TraverseDecl(translation_unit) ||
-      !google::protobuf::TextFormat::Print(tu, &text_os)) {
+  std::set<std::string> type_cache;
+  std::unique_ptr<abi_util::IRDumper> ir_dumper =
+      abi_util::IRDumper::CreateIRDumper("protobuf", out_dump_name_);
+  HeaderASTVisitor v(mangle_contextp.get(), &ctx, cip_, file_name_,
+                     exported_headers_, translation_unit, &type_cache,
+                     ir_dumper.get());
+  if (!v.TraverseDecl(translation_unit) || !ir_dumper->Dump()) {
     llvm::errs() << "Serialization to ostream failed\n";
     ::exit(1);
   }
diff --git a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.h b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.h
index f3e6f8c..569936b 100644
--- a/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.h
+++ b/vndk/tools/header-checker/header-abi-dumper/src/ast_processing.h
@@ -21,6 +21,8 @@
 #include "proto/abi_dump.pb.h"
 #pragma clang diagnostic pop
 
+#include <ir_representation.h>
+
 #include <clang/AST/AST.h>
 #include <clang/AST/ASTConsumer.h>
 #include <clang/AST/Mangle.h>
@@ -33,13 +35,14 @@
 class HeaderASTVisitor
     : public clang::RecursiveASTVisitor<HeaderASTVisitor> {
  public:
-  HeaderASTVisitor(abi_dump::TranslationUnit *tu_ptr,
-                   clang::MangleContext *mangle_contextp,
+  HeaderASTVisitor(clang::MangleContext *mangle_contextp,
                    clang::ASTContext *ast_contextp,
                    const clang::CompilerInstance *compiler_instance_p,
                    const std::string &current_file_name,
                    const std::set<std::string> &exported_headers,
-                   const clang::Decl *tu_decl);
+                   const clang::Decl *tu_decl,
+                   std::set<std::string> *type_cache,
+                   abi_util::IRDumper *ir_dumper);
 
   bool VisitRecordDecl(const clang::RecordDecl *decl);
 
@@ -57,7 +60,6 @@
   }
 
  private:
-  abi_dump::TranslationUnit *tu_ptr_;
   clang::MangleContext *mangle_contextp_;
   clang::ASTContext *ast_contextp_;
   const clang::CompilerInstance *cip_;
@@ -65,6 +67,11 @@
   const std::set<std::string> &exported_headers_;
   // To optimize recursion into only exported abi.
   const clang::Decl *tu_decl_;
+  std::set<std::string> *type_cache_;
+  abi_util::IRDumper *ir_dumper_;
+  // We cache the source file an AST node corresponds to, to avoid repeated
+  // calls to "realpath".
+  std::map<const clang::Decl *, std::string> decl_to_source_file_cache_;
 };
 
 class HeaderASTConsumer : public clang::ASTConsumer {
@@ -83,4 +90,4 @@
   std::set<std::string> exported_headers_;
 };
 
-#endif  // AST_PROCESSING_H_
+#endif // AST_PROCESSING_H_
diff --git a/vndk/tools/header-checker/header-abi-linker/src/header_abi_linker.cpp b/vndk/tools/header-checker/header-abi-linker/src/header_abi_linker.cpp
index 96616d1..b02092d 100644
--- a/vndk/tools/header-checker/header-abi-linker/src/header_abi_linker.cpp
+++ b/vndk/tools/header-checker/header-abi-linker/src/header_abi_linker.cpp
@@ -85,16 +85,20 @@
 
   bool LinkAndDump();
 
+  template <typename T>
+  static std::string GetLinkageName(T &element) {
+    return element.type_info().linker_set_key();
+  }
+  template <typename T>
+  static std::string GetSourceFile(T &element) {
+    return element.type_info().source_file();
+  }
  private:
-  bool LinkRecords(const abi_dump::TranslationUnit &dump_tu,
-                   abi_dump::TranslationUnit *linked_tu);
-
+  bool LinkTypes(const abi_dump::TranslationUnit &dump_tu,
+                 abi_dump::TranslationUnit *linked_tu);
   bool LinkFunctions(const abi_dump::TranslationUnit &dump_tu,
                      abi_dump::TranslationUnit *linked_tu);
 
-  bool LinkEnums(const abi_dump::TranslationUnit &dump_tu,
-                 abi_dump::TranslationUnit *linked_tu);
-
   bool LinkGlobalVars(const abi_dump::TranslationUnit &dump_tu,
                       abi_dump::TranslationUnit *linked_tu);
 
@@ -110,6 +114,8 @@
 
   bool ParseSoFile();
 
+  bool AddElfSymbols(abi_dump::TranslationUnit *linked_tu);
+
  private:
   const std::vector<std::string> &dump_files_;
   const std::vector<std::string> &exported_header_dirs_;
@@ -120,9 +126,8 @@
   const std::string &api_;
   // TODO: Add to a map of std::sets instead.
   std::set<std::string> exported_headers_;
-  std::set<std::string> record_decl_set_;
+  std::set<std::string> types_set_;
   std::set<std::string> function_decl_set_;
-  std::set<std::string> enum_decl_set_;
   std::set<std::string> globvar_decl_set_;
   // Version Script Regex Matching.
   std::set<std::string> functions_regex_matched_set;
@@ -132,12 +137,32 @@
   std::regex globvars_vs_regex_;
 };
 
+template <typename T, typename Iterable>
+static bool AddElfSymbols(google::protobuf::RepeatedPtrField<T> *dst,
+                          Iterable symbols) {
+  for (auto &&symbol : symbols) {
+    auto *added_symbol = dst->Add();
+    if (added_symbol == nullptr) {
+      return false;
+    }
+    added_symbol->set_name(symbol);
+  }
+  return true;
+}
+
+// To be called right after parsing the .so file / version script.
+bool HeaderAbiLinker::AddElfSymbols(abi_dump::TranslationUnit *linked_tu) {
+
+  return ::AddElfSymbols(linked_tu->mutable_elf_functions(), function_decl_set_)
+      && ::AddElfSymbols(linked_tu->mutable_elf_objects(), globvar_decl_set_);
+}
+
 bool HeaderAbiLinker::LinkAndDump() {
   abi_dump::TranslationUnit linked_tu;
   std::ofstream text_output(out_dump_name_);
   google::protobuf::io::OstreamOutputStream text_os(&text_output);
-  // If a version script is available, we use that as a filter.
-  if (version_script.empty()) {
+  // If the user specifies that a version script should be used, use that.
+  if (!so_file_.empty()) {
     exported_headers_ =
         abi_util::CollectAllExportedHeaders(exported_header_dirs_);
     if (!ParseSoFile()) {
@@ -149,20 +174,20 @@
     return false;
   }
 
+  AddElfSymbols(&linked_tu);
+
   for (auto &&i : dump_files_) {
     abi_dump::TranslationUnit dump_tu;
     std::ifstream input(i);
     google::protobuf::io::IstreamInputStream text_is(&input);
     if (!google::protobuf::TextFormat::Parse(&text_is, &dump_tu) ||
-        !LinkRecords(dump_tu, &linked_tu) ||
+        !LinkTypes(dump_tu, &linked_tu) ||
         !LinkFunctions(dump_tu, &linked_tu) ||
-        !LinkEnums(dump_tu, &linked_tu) ||
         !LinkGlobalVars(dump_tu, &linked_tu)) {
       llvm::errs() << "Failed to link elements\n";
       return false;
     }
   }
-
   if (!google::protobuf::TextFormat::Print(linked_tu, &text_os)) {
     llvm::errs() << "Serialization to ostream failed\n";
     return false;
@@ -170,22 +195,6 @@
   return true;
 }
 
-static std::string GetSymbol(const abi_dump::RecordDecl &element) {
-  return element.mangled_record_name();
-}
-
-static std::string GetSymbol(const abi_dump::FunctionDecl &element) {
-  return element.mangled_function_name();
-}
-
-static std::string GetSymbol(const abi_dump::EnumDecl &element) {
-  return element.basic_abi().linker_set_key();
-}
-
-static std::string GetSymbol(const abi_dump::GlobalVarDecl &element) {
-  return element.basic_abi().linker_set_key();
-}
-
 static bool QueryRegexMatches(std::set<std::string> *regex_matched_link_set,
                               const std::regex *vs_regex,
                               const std::string &symbol) {
@@ -219,10 +228,10 @@
   return std::regex(all_regex_match_str);
 }
 
+//TODO: make linking decls multi-threaded b/63590537.
 template <typename T>
 inline bool HeaderAbiLinker::LinkDecl(
-    google::protobuf::RepeatedPtrField<T> *dst,
-    std::set<std::string> *link_set,
+    google::protobuf::RepeatedPtrField<T> *dst, std::set<std::string> *link_set,
     std::set<std::string> *regex_matched_link_set, const std::regex *vs_regex,
     const google::protobuf::RepeatedPtrField<T> &src, bool use_version_script) {
   assert(dst != nullptr);
@@ -230,18 +239,20 @@
   for (auto &&element : src) {
     // If we are not using a version script and exported headers are available,
     // filter out unexported abi.
-    if (!exported_headers_.empty() &&
-        exported_headers_.find(element.source_file()) ==
+    std::string source_file = GetSourceFile(element);
+    // Builtin types will not have source file information.
+    if (!exported_headers_.empty() && !source_file.empty() &&
+        exported_headers_.find(source_file) ==
         exported_headers_.end()) {
       continue;
     }
+    std::string element_str = GetLinkageName(element);
     // Check for the existence of the element in linked dump / symbol file.
     if (!use_version_script) {
-        if (!link_set->insert(element.basic_abi().linker_set_key()).second) {
+      if (!link_set->insert(element_str).second) {
         continue;
-        }
+      }
     } else {
-      std::string element_str = GetSymbol(element);
       std::set<std::string>::iterator it =
           link_set->find(element_str);
       if (it == link_set->end()) {
@@ -263,13 +274,52 @@
   return true;
 }
 
-bool HeaderAbiLinker::LinkRecords(const abi_dump::TranslationUnit &dump_tu,
-                                  abi_dump::TranslationUnit *linked_tu) {
+
+template<>
+std::string HeaderAbiLinker::GetLinkageName<const abi_dump::FunctionDecl> (
+    const abi_dump::FunctionDecl &element) {
+  return element.linker_set_key();
+}
+
+template<>
+std::string HeaderAbiLinker::GetSourceFile<const abi_dump::FunctionDecl> (
+    const abi_dump::FunctionDecl &element) {
+  return element.source_file();
+}
+
+template<>
+std::string HeaderAbiLinker::GetLinkageName<const abi_dump::GlobalVarDecl> (
+    const abi_dump::GlobalVarDecl &element) {
+  return element.linker_set_key();
+}
+
+template<>
+std::string HeaderAbiLinker::GetSourceFile<const abi_dump::GlobalVarDecl> (
+    const abi_dump::GlobalVarDecl &element) {
+  return element.source_file();
+}
+
+bool HeaderAbiLinker::LinkTypes(const abi_dump::TranslationUnit &dump_tu,
+                                abi_dump::TranslationUnit *linked_tu) {
   assert(linked_tu != nullptr);
-  // Even if version scripts are available we take in records, since the symbols
-  // in the version script might reference a record exposed by the library.
-  return LinkDecl(linked_tu->mutable_records(), &record_decl_set_, nullptr,
-                  nullptr, dump_tu.records(), false);
+  // Even if version scripts are available we take in types, since the symbols
+  // in the version script might reference a type exposed by the library.
+  return LinkDecl(linked_tu->mutable_record_types(), &types_set_, nullptr,
+                  nullptr, dump_tu.record_types(), false) &&
+      LinkDecl(linked_tu->mutable_enum_types(), &types_set_, nullptr,
+               nullptr, dump_tu.enum_types(), false) &&
+      LinkDecl(linked_tu->mutable_builtin_types(), &types_set_, nullptr,
+               nullptr, dump_tu.builtin_types(), false) &&
+      LinkDecl(linked_tu->mutable_pointer_types(), &types_set_, nullptr,
+               nullptr, dump_tu.pointer_types(), false) &&
+      LinkDecl(linked_tu->mutable_rvalue_reference_types(), &types_set_, nullptr,
+               nullptr, dump_tu.rvalue_reference_types(), false) &&
+      LinkDecl(linked_tu->mutable_lvalue_reference_types(), &types_set_, nullptr,
+               nullptr, dump_tu.lvalue_reference_types(), false) &&
+      LinkDecl(linked_tu->mutable_array_types(), &types_set_, nullptr,
+               nullptr, dump_tu.array_types(), false) &&
+      LinkDecl(linked_tu->mutable_qualified_types(), &types_set_, nullptr,
+               nullptr, dump_tu.qualified_types(), false);
 }
 
 bool HeaderAbiLinker::LinkFunctions(const abi_dump::TranslationUnit &dump_tu,
@@ -281,15 +331,6 @@
                   (!version_script_.empty() || !so_file_.empty()));
 }
 
-bool HeaderAbiLinker::LinkEnums(const abi_dump::TranslationUnit &dump_tu,
-                                abi_dump::TranslationUnit *linked_tu) {
-  assert(linked_tu != nullptr);
-  // Even if version scripts are available we take in records, since the symbols
-  // in the version script might reference an enum exposed by the library.
-  return LinkDecl(linked_tu->mutable_enums(), &enum_decl_set_, nullptr,
-                  nullptr, dump_tu.enums(), false);
-}
-
 bool HeaderAbiLinker::LinkGlobalVars(const abi_dump::TranslationUnit &dump_tu,
                                      abi_dump::TranslationUnit *linked_tu) {
   assert(linked_tu != nullptr);
@@ -345,6 +386,10 @@
 int main(int argc, const char **argv) {
   GOOGLE_PROTOBUF_VERIFY_VERSION;
   llvm::cl::ParseCommandLineOptions(argc, argv, "header-linker");
+  if (so_file.empty() && version_script.empty()) {
+    llvm::errs() << "One of -so or -v needs to be specified\n";
+    return -1;
+  }
   if (no_filter) {
     static_cast<std::vector<std::string> &>(exported_header_dirs).clear();
   }
diff --git a/vndk/tools/header-checker/header-abi-util/include/header_abi_util.h b/vndk/tools/header-checker/header-abi-util/include/header_abi_util.h
index b335cdd..5f18ab7 100644
--- a/vndk/tools/header-checker/header-abi-util/include/header_abi_util.h
+++ b/vndk/tools/header-checker/header-abi-util/include/header_abi_util.h
@@ -18,6 +18,7 @@
 #include <llvm/Support/Endian.h>
 #include <llvm/Support/raw_ostream.h>
 
+#include <map>
 #include <regex>
 #include <set>
 #include <string>
@@ -128,4 +129,60 @@
   bool IsSymbolExported(const Elf_Sym *elf_sym) const;
 };
 
+template <typename T, typename K>
+std::vector<T> FindRemovedElements(
+    const std::map<K, T> &old_elements_map,
+    const std::map<K, T> &new_elements_map) {
+  std::vector<T> removed_elements;
+  for (auto &&map_element : old_elements_map) {
+      auto element_key = map_element.first;
+      auto new_element = new_elements_map.find(element_key);
+      if (new_element == new_elements_map.end()) {
+        removed_elements.emplace_back(map_element.second);
+      }
+  }
+  return removed_elements;
+}
+
+template <typename T, typename F, typename K, typename Iterable>
+inline void AddToMap(std::map<K, T> *dst, Iterable &src, F get_key) {
+  for (auto &&element : src) {
+    dst->insert(std::make_pair(get_key(&element), &element));
+  }
+}
+
+template <typename F, typename K, typename Iterable>
+inline void AddToSet(std::set<K> *dst, Iterable &src, F get_key) {
+  for (auto &&element : src) {
+    dst->insert(get_key(element));
+  }
+}
+
+template <typename K, typename T>
+std::vector<std::pair<T, T>> FindCommonElements(
+    const std::map<K, T> &old_elements_map,
+    const std::map<K, T> &new_elements_map) {
+  std::vector<std::pair<T, T>> common_elements;
+  typename std::map<K, T>::const_iterator old_element =
+      old_elements_map.begin();
+  typename std::map<K, T>::const_iterator new_element =
+      new_elements_map.begin();
+  while (old_element != old_elements_map.end() &&
+         new_element != new_elements_map.end()) {
+    if (old_element->first == new_element->first) {
+      common_elements.emplace_back(std::make_pair(
+          old_element->second, new_element->second));
+      old_element++;
+      new_element++;
+      continue;
+    }
+    if (old_element->first < new_element->first) {
+      old_element++;
+    } else {
+      new_element++;
+    }
+  }
+  return common_elements;
+}
+
 } // namespace abi_util
diff --git a/vndk/tools/header-checker/header-abi-util/include/ir_representation.h b/vndk/tools/header-checker/header-abi-util/include/ir_representation.h
new file mode 100644
index 0000000..0567d0e
--- /dev/null
+++ b/vndk/tools/header-checker/header-abi-util/include/ir_representation.h
@@ -0,0 +1,1126 @@
+// 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 IR_
+#define IR_
+
+#include <map>
+#include <regex>
+#include <set>
+#include <string>
+#include <vector>
+#include <memory>
+
+// Classes which act as middle-men between clang AST parsing routines and
+// message format specific dumpers.
+namespace abi_util {
+
+enum CompatibilityStatusIR {
+  Compatible = 0,
+  UnreferencedChanges = 1,
+  Extension = 4,
+  Incompatible = 8
+};
+
+static inline CompatibilityStatusIR operator|(CompatibilityStatusIR f,
+                                              CompatibilityStatusIR s) {
+  return static_cast<CompatibilityStatusIR>(
+      static_cast<std::underlying_type<CompatibilityStatusIR>::type>(f) |
+      static_cast<std::underlying_type<CompatibilityStatusIR>::type>(s));
+}
+
+static inline CompatibilityStatusIR operator&(
+    CompatibilityStatusIR f, CompatibilityStatusIR s) {
+  return static_cast<CompatibilityStatusIR>(
+      static_cast<std::underlying_type<CompatibilityStatusIR>::type>(f) &
+      static_cast<std::underlying_type<CompatibilityStatusIR>::type>(s));
+}
+
+enum AccessSpecifierIR {
+  PublicAccess = 1,
+  ProtectedAccess = 2,
+  PrivateAccess = 3
+};
+
+enum LinkableMessageKind {
+  RecordTypeKind,
+  EnumTypeKind,
+  PointerTypeKind,
+  QualifiedTypeKind,
+  ArrayTypeKind,
+  LvalueReferenceTypeKind,
+  RvalueReferenceTypeKind,
+  BuiltinTypeKind,
+  FunctionKind,
+  GlobalVarKind
+};
+
+class LinkableMessageIR {
+ public:
+  const std::string &GetLinkerSetKey() const {
+    return linker_set_key_;
+  }
+
+  void SetSourceFile(const std::string &source_file) {
+    source_file_ = source_file;
+  }
+
+  void SetLinkerSetKey(const std::string &linker_set_key) {
+    linker_set_key_ = linker_set_key;
+  }
+
+  const std::string &GetSourceFile() const {
+    return source_file_;
+  }
+
+  virtual LinkableMessageKind GetKind() const = 0;
+
+  virtual ~LinkableMessageIR() {}
+
+ protected:
+  // The source file where this message comes from. This will be an empty string
+  // for built-in types
+  std::string source_file_;
+  std::string linker_set_key_;
+};
+
+class BasicTypeInfoIR {
+ public:
+  BasicTypeInfoIR(const std::string &name, const std::string &type,
+                  const std::string linker_set_key, uint64_t size,
+                  uint32_t alignment)
+      : name_(name), referenced_type_(type), linker_set_key_(linker_set_key) ,
+        size_(size), alignment_(alignment) { }
+
+  BasicTypeInfoIR() { }
+
+  std::string GetLinkerSetKey() {
+    return linker_set_key_;
+  }
+
+ protected:
+  std::string name_;
+  std::string referenced_type_;
+  std::string linker_set_key_;
+  uint64_t size_;
+  uint32_t alignment_;
+};
+
+// TODO: Break this up into types with sizes and those without types ?
+class TypeIR : public LinkableMessageIR {
+ public:
+  void SetName(const std::string &name) {
+    name_ = name;
+  }
+
+  const std::string &GetName() const {
+    return name_;
+  }
+
+  void SetReferencedType(const std::string &type) {
+    referenced_type_ = type;
+  }
+
+  const std::string &GetReferencedType() const {
+    return referenced_type_;
+  }
+
+  void SetSize(uint64_t size) {
+    size_ = size;
+  }
+  uint64_t GetSize() const {
+   return size_;
+  }
+  void SetAlignment(uint32_t alignment) {
+    alignment_ = alignment;
+  }
+  uint32_t GetAlignment() const {
+    return alignment_;
+  }
+  ~TypeIR() override { }
+
+ protected:
+  std::string name_;
+  std::string referenced_type_;
+  uint64_t size_;
+  uint32_t alignment_;
+};
+
+class VTableComponentIR {
+ public:
+  enum Kind {
+    VCallOffset = 0,
+    VBaseOffset = 1,
+    OffsetToTop = 2,
+    RTTI = 3,
+    FunctionPointer = 4,
+    CompleteDtorPointer = 5,
+    DeletingDtorPointer = 6,
+    UnusedFunctionPointer = 7
+  };
+
+  VTableComponentIR(const std::string &name, Kind kind, int64_t value)
+      : component_name_(name), kind_(kind), value_(value) { }
+
+  VTableComponentIR() { }
+
+  Kind GetKind() const {
+    return kind_;
+  }
+
+  int64_t GetValue() const {
+    return value_;
+  }
+
+  const std::string &GetName() const {
+    return component_name_;
+  }
+
+ protected:
+  std::string component_name_;
+  Kind kind_;
+  int64_t value_;
+};
+
+class VTableLayoutIR {
+ public:
+  void AddVTableComponent(VTableComponentIR &&vtable_component) {
+    vtable_components_.emplace_back(std::move(vtable_component));
+  }
+
+  const std::vector<VTableComponentIR> &GetVTableComponents() const {
+    return vtable_components_;
+  }
+
+  uint64_t GetVTableNumEntries() const {
+    return vtable_components_.size();
+  }
+
+ protected:
+  std::vector<VTableComponentIR> vtable_components_;
+};
+
+class CXXBaseSpecifierIR {
+ public:
+  CXXBaseSpecifierIR(const std::string &type, bool is_virtual,
+                     AccessSpecifierIR access) :
+    referenced_type_(type), is_virtual_(is_virtual), access_(access) { }
+
+  CXXBaseSpecifierIR() { }
+
+  const std::string &GetReferencedType() const {
+    return referenced_type_;
+  }
+
+  bool IsVirtual() const {
+    return is_virtual_;
+  }
+
+  AccessSpecifierIR GetAccess() const {
+    return access_;
+  }
+
+ protected:
+  std::string referenced_type_;
+  bool is_virtual_;
+  AccessSpecifierIR access_;
+};
+
+class TemplateElementIR {
+ public:
+  TemplateElementIR(std::string &&type)
+      : referenced_type_(std::move(type)) { }
+
+  TemplateElementIR(const std::string &type)
+      : referenced_type_(type) { }
+
+  TemplateElementIR() { }
+
+  const std::string &GetReferencedType() const {
+    return referenced_type_;
+  }
+
+ protected:
+  std::string referenced_type_;
+};
+
+class TemplateInfoIR {
+ public:
+  void AddTemplateElement(TemplateElementIR &&element) {
+    template_elements_.emplace_back(element);
+  }
+
+  const std::vector<TemplateElementIR> &GetTemplateElements() const {
+    return template_elements_;
+  }
+
+ protected:
+  std::vector<TemplateElementIR> template_elements_;
+};
+
+class TemplatedArtifactIR {
+ public:
+  void SetTemplateInfo(TemplateInfoIR &&template_info) {
+    template_info_ = std::move(template_info);
+  }
+
+  const std::vector<TemplateElementIR> &GetTemplateElements() const {
+    return template_info_.GetTemplateElements();
+  }
+
+ protected:
+  TemplateInfoIR template_info_;
+};
+
+class RecordFieldIR {
+ public:
+  RecordFieldIR(const std::string &name, const std::string &type,
+                uint64_t offset, AccessSpecifierIR access)
+      : name_(name), referenced_type_(type), offset_(offset),
+        access_(access) { }
+
+  RecordFieldIR() { }
+
+  const std::string &GetName() const {
+    return name_;
+  }
+
+  const std::string &GetReferencedType() const {
+    return referenced_type_;
+  }
+
+  uint64_t GetOffset() const {
+    return offset_;
+  }
+
+  AccessSpecifierIR GetAccess() const {
+    return access_;
+  }
+
+ protected:
+  std::string name_;
+  std::string referenced_type_;
+  uint64_t offset_;
+  AccessSpecifierIR access_;
+};
+
+class RecordTypeIR: public TypeIR, public TemplatedArtifactIR {
+ public:
+  enum RecordKind {
+    struct_kind,
+    class_kind,
+    union_kind
+  };
+
+  void AddRecordField(RecordFieldIR &&field) {
+    fields_.emplace_back(std::move(field));
+  }
+
+  void SetRecordFields(std::vector<RecordFieldIR> &&fields) {
+    fields_ = std::move(fields);
+  }
+
+  void SetVTableLayout(VTableLayoutIR &&vtable_layout) {
+    vtable_layout_ = std::move(vtable_layout);
+  }
+
+  const VTableLayoutIR &GetVTableLayout() const {
+    return vtable_layout_;
+  }
+
+  void AddCXXBaseSpecifier(CXXBaseSpecifierIR &&base_specifier) {
+    bases_.emplace_back(std::move(base_specifier));
+  }
+
+  void SetCXXBaseSpecifiers(std::vector<CXXBaseSpecifierIR> &&bases) {
+    bases_ = std::move(bases);
+  }
+
+  const std::vector<CXXBaseSpecifierIR> &GetBases() const {
+    return bases_;
+  }
+
+  void SetAccess(AccessSpecifierIR access) { access_ = access;}
+
+  AccessSpecifierIR GetAccess() const {
+    return access_;
+  }
+
+  const std::vector<RecordFieldIR> &GetFields() const {
+    return fields_;
+  }
+
+  LinkableMessageKind GetKind() const override {
+    return LinkableMessageKind::RecordTypeKind;
+  }
+
+  uint64_t GetVTableNumEntries() const {
+    return vtable_layout_.GetVTableNumEntries();
+  }
+
+  void SetRecordKind(RecordKind record_kind) {
+    record_kind_ = record_kind;
+  }
+
+  RecordKind GetRecordKind() const {
+    return record_kind_;
+  }
+
+  void SetAnonymity(bool is_anonymous) {
+    is_anonymous_ = is_anonymous;
+  }
+
+  bool IsAnonymous() const {
+    return is_anonymous_;
+  }
+
+ protected:
+  std::vector<RecordFieldIR> fields_;
+  VTableLayoutIR vtable_layout_;
+  std::vector<CXXBaseSpecifierIR> bases_;
+  AccessSpecifierIR access_;
+  bool is_anonymous_;
+  RecordKind record_kind_;
+};
+
+class EnumFieldIR {
+ public:
+  EnumFieldIR(const std::string &name, int value)
+      : name_(name), value_(value) { }
+  const std::string &GetName() const {
+    return name_;
+  }
+
+  int GetValue() const {
+    return value_;
+  }
+
+ protected:
+  std::string name_;
+  int value_;
+};
+
+class EnumTypeIR : public TypeIR {
+ public:
+  // Add Methods to get information from the IR.
+  void AddEnumField(EnumFieldIR &&field) {
+    fields_.emplace_back(std::move(field));
+  }
+
+  void SetAccess(AccessSpecifierIR access) { access_ = access;}
+
+  LinkableMessageKind GetKind() const override {
+    return LinkableMessageKind::EnumTypeKind;
+  }
+
+  AccessSpecifierIR GetAccess() const {
+    return access_;
+  }
+
+  void SetUnderlyingType(std::string &&underlying_type) {
+    underlying_type_ = std::move(underlying_type);
+  }
+
+  void SetUnderlyingType(const std::string &underlying_type) {
+    underlying_type_ = underlying_type;
+  }
+
+  const std::string &GetUnderlyingType() const {
+    return underlying_type_;
+  }
+
+  void SetFields(std::vector<EnumFieldIR> &&fields) {
+    fields_ = std::move(fields);
+  }
+
+  const std::vector<EnumFieldIR> &GetFields() const {
+    return fields_;
+  }
+
+ protected:
+  std::vector<EnumFieldIR> fields_;
+  std::string underlying_type_;
+  AccessSpecifierIR access_;
+};
+
+class ArrayTypeIR : public TypeIR {
+ public:
+  LinkableMessageKind GetKind() const override {
+    return LinkableMessageKind::ArrayTypeKind;
+  }
+};
+
+class PointerTypeIR : public TypeIR {
+ public:
+  LinkableMessageKind GetKind() const override {
+    return LinkableMessageKind::PointerTypeKind;
+  }
+};
+
+class BuiltinTypeIR : public TypeIR {
+ public:
+  void SetSignedness(bool is_unsigned) {
+    is_unsigned_ = is_unsigned;
+  }
+
+  bool IsUnsigned() const {
+    return is_unsigned_;
+  }
+
+  void SetIntegralType(bool is_integral_type) {
+    is_integral_type_ = is_integral_type;
+  }
+
+  bool IsIntegralType() const {
+    return is_integral_type_;
+  }
+
+ public:
+  LinkableMessageKind GetKind() const override {
+    return LinkableMessageKind::BuiltinTypeKind;
+  }
+
+ protected:
+  bool is_unsigned_;
+  bool is_integral_type_;
+};
+
+class LvalueReferenceTypeIR : public TypeIR {
+ public:
+  LinkableMessageKind GetKind() const override {
+    return LinkableMessageKind::LvalueReferenceTypeKind;
+  }
+};
+
+class RvalueReferenceTypeIR : public TypeIR {
+ public:
+  LinkableMessageKind GetKind() const override {
+    return LinkableMessageKind::RvalueReferenceTypeKind;
+  }
+};
+
+class QualifiedTypeIR : public TypeIR {
+ public:
+  void SetConstness(bool is_const) {
+    is_const_ = is_const;
+  }
+
+  bool IsConst() const {
+    return is_const_;
+  }
+
+  void SetRestrictedness(bool is_restricted) {
+    is_restricted_ = is_restricted;
+  }
+
+  bool IsRestricted() const {
+    return is_restricted_;
+  }
+
+  void SetVolatility(bool is_volatile) {
+    is_volatile_ = is_volatile;
+  }
+
+  bool IsVolatile() const {
+    return is_volatile_;
+  }
+
+ public:
+  LinkableMessageKind GetKind() const override {
+    return LinkableMessageKind::QualifiedTypeKind;
+  }
+
+ protected:
+  bool is_const_;
+  bool is_restricted_;
+  bool is_volatile_;
+};
+
+class GlobalVarIR: public LinkableMessageIR {
+ public:
+  // Add Methods to get information from the IR.
+  void SetReferencedType(const std::string &type) {
+    referenced_type_ = type;
+  }
+
+  const std::string &GetReferencedType() const {
+    return referenced_type_;
+  }
+
+  void SetName(std::string &&name) {
+    name_ = std::move(name);
+  }
+
+  void SetName(const std::string &name) {
+    name_ = name;
+  }
+
+  const std::string &GetName() const {
+    return name_;
+  }
+
+  AccessSpecifierIR GetAccess() const {
+    return access_;
+  }
+
+  LinkableMessageKind GetKind() const override {
+    return LinkableMessageKind::GlobalVarKind;
+  }
+
+ protected:
+  std::string referenced_type_; // underlying type
+  std::string name_;
+  AccessSpecifierIR access_;
+};
+
+class ParamIR {
+ public:
+  ParamIR(const std::string &type, bool is_default) :
+    referenced_type_(type) , is_default_(is_default) {}
+
+  const std::string &GetReferencedType() const {
+    return referenced_type_;
+  }
+
+  bool GetIsDefault() const {
+    return is_default_;
+  }
+
+ protected:
+  std::string referenced_type_;
+  bool is_default_;
+};
+
+class FunctionIR : public LinkableMessageIR, public TemplatedArtifactIR {
+ public:
+  void SetReturnType(const std::string &type) {
+    return_type_ = type;
+  }
+
+  const std::string &GetReturnType() const {
+    return return_type_;
+  }
+
+  void AddParameter(ParamIR &&parameter) {
+    parameters_.emplace_back(std::move(parameter));
+  }
+
+  void SetAccess(AccessSpecifierIR access) {
+    access_ = access;
+  }
+
+  AccessSpecifierIR GetAccess() const {
+    return access_;
+  }
+
+  LinkableMessageKind GetKind() const override {
+    return LinkableMessageKind::FunctionKind;
+  }
+
+  const std::vector<ParamIR> &GetParameters() const {
+    return parameters_;
+  }
+
+  void SetName(const std::string &name) {
+    name_ = name;
+  }
+
+  const std::string &GetName() const {
+    return name_;
+  }
+
+ protected:
+    std::string return_type_; // return type reference
+    std::string linkage_name_;
+    std::string name_;
+    std::vector<ParamIR> parameters_;
+    AccessSpecifierIR access_;
+};
+
+class ElfSymbolIR {
+ public:
+  enum ElfSymbolKind {
+    ElfFunctionKind,
+    ElfObjectKind
+  };
+
+  const std::string GetName() const {
+    return name_;
+  }
+
+  ElfSymbolIR(const std::string &name) : name_(name) { }
+
+  virtual ElfSymbolKind GetKind() const = 0;
+
+  virtual ~ElfSymbolIR() { }
+
+ protected:
+  std::string name_;
+};
+
+class ElfFunctionIR : public ElfSymbolIR{
+ public:
+  ElfSymbolKind GetKind() const override {
+    return ElfFunctionKind;
+  }
+
+  ElfFunctionIR(const std::string &name) : ElfSymbolIR(name) { }
+};
+
+class ElfObjectIR : public ElfSymbolIR {
+ public:
+  ElfSymbolKind GetKind() const override {
+    return ElfObjectKind;
+  }
+
+  ElfObjectIR(const std::string &name) : ElfSymbolIR(name) { }
+};
+
+class IRDumper {
+ public:
+  IRDumper(const std::string &dump_path) : dump_path_(dump_path) { }
+
+  static std::unique_ptr<IRDumper> CreateIRDumper(const std::string &type,
+                                                  const std::string &dump_path);
+
+  virtual bool AddLinkableMessageIR(const LinkableMessageIR *) = 0;
+
+  virtual bool Dump() = 0;
+
+  virtual ~IRDumper() {}
+
+ protected:
+  const std::string &dump_path_;
+};
+
+class TextFormatToIRReader {
+ public:
+  TextFormatToIRReader(const std::string &dump_path) : dump_path_(dump_path) { }
+
+  const std::vector<FunctionIR> &GetFunctions() const {
+    return functions_;
+  }
+
+  const std::vector<GlobalVarIR> &GetGlobalVariables() const {
+    return global_variables_;
+  }
+
+  const std::vector<RecordTypeIR> &GetRecordTypes() const {
+    return record_types_;
+  }
+
+  const std::vector<EnumTypeIR> &GetEnumTypes() const {
+    return enum_types_;
+  }
+
+  const std::vector<LvalueReferenceTypeIR> &GetLvalueReferenceTypes() const {
+    return lvalue_reference_types_;
+  }
+
+  const std::vector<RvalueReferenceTypeIR> &GetRvalueReferenceTypes() const {
+    return rvalue_reference_types_;
+  }
+
+  const std::vector<QualifiedTypeIR> &GetQualifiedTypes() const {
+    return qualified_types_;
+  }
+
+  const std::vector<ArrayTypeIR> &GetArrayTypes() const {
+    return array_types_;
+  }
+
+  const std::vector<PointerTypeIR> &GetPointerTypes() const {
+    return pointer_types_;
+  }
+
+  const std::vector<BuiltinTypeIR> &GetBuiltinTypes() const {
+    return builtin_types_;
+  }
+
+  const std::vector<ElfFunctionIR> &GetElfFunctions() const {
+    return elf_functions_;
+  }
+
+  const std::vector<ElfObjectIR> &GetElfObjects() const {
+    return elf_objects_;
+  }
+
+  virtual bool ReadDump() = 0;
+
+  virtual ~TextFormatToIRReader() { }
+
+  static std::unique_ptr<TextFormatToIRReader> CreateTextFormatToIRReader(
+      const std::string &text_format, const std::string &dump_path);
+
+ protected:
+  const std::string &dump_path_;
+  std::vector<FunctionIR> functions_;
+  std::vector<GlobalVarIR> global_variables_;
+  std::vector<RecordTypeIR> record_types_;
+  std::vector<EnumTypeIR> enum_types_;
+  std::vector<PointerTypeIR> pointer_types_;
+  std::vector<LvalueReferenceTypeIR> lvalue_reference_types_;
+  std::vector<RvalueReferenceTypeIR> rvalue_reference_types_;
+  std::vector<ArrayTypeIR> array_types_;
+  std::vector<BuiltinTypeIR> builtin_types_;
+  std::vector<QualifiedTypeIR> qualified_types_;
+  std::vector<ElfFunctionIR> elf_functions_;
+  std::vector<ElfObjectIR> elf_objects_;
+};
+
+class DiffMessageIR {
+ public:
+  virtual LinkableMessageKind Kind() const = 0;
+  void SetName(const std::string &name) {
+    name_ = name;
+  }
+
+  const std::string &GetName() const {
+    return name_;
+  }
+
+  virtual ~DiffMessageIR() { }
+
+ protected:
+  std::string name_;
+};
+
+class AccessSpecifierDiffIR {
+ public:
+  AccessSpecifierDiffIR(AccessSpecifierIR old_access,
+                        AccessSpecifierIR new_access)
+      : old_access_(old_access), new_access_(new_access) { }
+
+ protected:
+  AccessSpecifierIR old_access_;
+  AccessSpecifierIR new_access_;
+};
+
+class TypeDiffIR {
+ public:
+  TypeDiffIR(std::pair<uint64_t, uint64_t> &&sizes,
+             std::pair<uint32_t, uint32_t> &&alignment)
+      : sizes_(std::move(sizes)), alignments_(std::move(alignment)) { }
+
+  const std::pair<uint64_t, uint64_t> &GetSizes() const {
+    return sizes_;
+  }
+
+  const std::pair<uint32_t, uint32_t> &GetAlignments() const {
+    return alignments_;
+  }
+
+ protected:
+  std::pair<uint64_t, uint64_t> sizes_;
+  std::pair<uint32_t, uint32_t> alignments_;
+};
+
+class VTableLayoutDiffIR {
+ public:
+  VTableLayoutDiffIR(const VTableLayoutIR &old_layout,
+                     const VTableLayoutIR &new_layout)
+      : old_layout_(old_layout), new_layout_(new_layout) { }
+
+  const VTableLayoutIR &GetOldVTable() const {
+    return old_layout_;
+  }
+
+  const VTableLayoutIR &GetNewVTable() const {
+    return new_layout_;
+  }
+
+ protected:
+  const VTableLayoutIR &old_layout_;
+  const VTableLayoutIR &new_layout_;
+};
+
+class RecordFieldDiffIR {
+ public:
+  RecordFieldDiffIR(const RecordFieldIR *old_field,
+                    const RecordFieldIR *new_field)
+      : old_field_(old_field), new_field_(new_field) { }
+  const RecordFieldIR *GetOldField() const {
+    return old_field_;
+  }
+
+  const RecordFieldIR *GetNewField() const {
+    return new_field_;
+  }
+
+ protected:
+  const RecordFieldIR *old_field_;
+  const RecordFieldIR *new_field_;
+};
+
+class CXXBaseSpecifierDiffIR {
+ public:
+  CXXBaseSpecifierDiffIR(
+      const std::vector<CXXBaseSpecifierIR> &old_base_specifiers,
+      const std::vector<CXXBaseSpecifierIR> &new_base_specifiers)
+      : old_base_specifiers_(old_base_specifiers),
+        new_base_specifiers_(new_base_specifiers) { }
+  const std::vector<CXXBaseSpecifierIR> &GetOldBases() const {
+    return old_base_specifiers_;
+  }
+
+  const std::vector<CXXBaseSpecifierIR> &GetNewBases() const {
+    return new_base_specifiers_;
+  }
+
+ protected:
+  const std::vector<CXXBaseSpecifierIR> &old_base_specifiers_;
+  const std::vector<CXXBaseSpecifierIR> &new_base_specifiers_;
+};
+
+class RecordTypeDiffIR : public DiffMessageIR {
+ public:
+  LinkableMessageKind Kind() const override {
+    return LinkableMessageKind::RecordTypeKind;
+  }
+
+  void SetFieldDiffs(std::vector<RecordFieldDiffIR> &&field_diffs) {
+    field_diffs_ = std::move(field_diffs);
+  }
+
+  const std::vector<RecordFieldDiffIR> &GetFieldDiffs() const {
+    return field_diffs_;
+  }
+
+  void SetFieldsRemoved(std::vector<const RecordFieldIR *> &&fields_removed) {
+    fields_removed_ = std::move(fields_removed);
+  }
+
+  const std::vector<const RecordFieldIR *> &GetFieldsRemoved() const {
+    return fields_removed_;
+  }
+
+  void SetVTableLayoutDiff(std::unique_ptr<VTableLayoutDiffIR> &&vtable_diffs) {
+    vtable_diffs_ = std::move(vtable_diffs);
+  }
+
+  void SetTypeDiff(std::unique_ptr<TypeDiffIR> &&type_diff) {
+    type_diff_ = std::move(type_diff);
+  }
+
+  void SetAccessDiff(std::unique_ptr<AccessSpecifierDiffIR> &&access_diff) {
+    access_diff_ = std::move(access_diff);
+  }
+
+  void SetBaseSpecifierDiffs(
+      std::unique_ptr<CXXBaseSpecifierDiffIR> &&base_diffs) {
+    base_specifier_diffs_ = std::move(base_diffs);
+  }
+
+  bool DiffExists() const {
+    return (type_diff_ != nullptr) || (vtable_diffs_ != nullptr) ||
+        (fields_removed_.size() != 0) || (field_diffs_.size() != 0) ||
+        (access_diff_ != nullptr) || (base_specifier_diffs_ != nullptr);
+  }
+
+  const TypeDiffIR *GetTypeDiff() const {
+    return type_diff_.get();
+  }
+
+  const VTableLayoutDiffIR *GetVTableLayoutDiff() const {
+    return vtable_diffs_.get();
+  }
+
+  const CXXBaseSpecifierDiffIR *GetBaseSpecifiers() const {
+    return base_specifier_diffs_.get();
+  }
+
+ protected:
+  // optional implemented with vector / std::unique_ptr.
+  std::unique_ptr<TypeDiffIR> type_diff_;
+  std::unique_ptr<VTableLayoutDiffIR> vtable_diffs_;
+  std::vector<RecordFieldDiffIR> field_diffs_;
+  std::vector<const RecordFieldIR *> fields_removed_;
+  std::unique_ptr<AccessSpecifierDiffIR> access_diff_;
+  std::unique_ptr<CXXBaseSpecifierDiffIR> base_specifier_diffs_;
+  // Template Diffs are not needed since they will show up in the linker set
+  // key.
+};
+
+class EnumFieldDiffIR {
+ public:
+  EnumFieldDiffIR(const EnumFieldIR *old_field, const EnumFieldIR *new_field)
+      : old_field_(old_field), new_field_(new_field) { }
+
+  const EnumFieldIR *GetOldField() const {
+    return old_field_;
+  }
+
+  const EnumFieldIR *GetNewField() const {
+    return new_field_;
+  }
+
+ protected:
+  const EnumFieldIR *old_field_;
+  const EnumFieldIR *new_field_;
+};
+
+class EnumTypeDiffIR : public DiffMessageIR {
+ public:
+  void SetFieldsRemoved(std::vector<const EnumFieldIR *> &&fields_removed) {
+    fields_removed_ = std::move(fields_removed);
+  }
+
+  const std::vector<const EnumFieldIR *> &GetFieldsRemoved() const {
+    return fields_removed_;
+  }
+
+  void SetFieldsAdded(std::vector<const EnumFieldIR *> &&fields_added) {
+    fields_added_ = std::move(fields_added);
+  }
+
+  const std::vector<const EnumFieldIR *> &GetFieldsAdded() const {
+    return fields_added_;
+  }
+
+  void SetFieldsDiff(std::vector<EnumFieldDiffIR> &&fields_diff) {
+    fields_diff_ = std::move(fields_diff);
+  }
+
+  const std::vector<EnumFieldDiffIR> &GetFieldsDiff() const {
+    return fields_diff_;
+  }
+
+  void SetUnderlyingTypeDiff(
+      std::unique_ptr<std::pair<std::string, std::string>> &&utype_diff) {
+    underlying_type_diff_ = std::move(utype_diff);
+  }
+
+  const std::pair<std::string, std::string> *GetUnderlyingTypeDiff() const {
+    return underlying_type_diff_.get();
+  }
+
+  bool IsExtended() const {
+    if (fields_removed_.size() == 0 && fields_diff_.size() == 0 &&
+        fields_added_.size() != 0) {
+        return true;
+    }
+
+    return false;
+  }
+
+  bool IsIncompatible() const {
+    if (fields_removed_.size() != 0 || fields_diff_.size() != 0) {
+        return true;
+    }
+
+    return false;
+  }
+
+  LinkableMessageKind Kind() const override {
+    return LinkableMessageKind::EnumTypeKind;
+  }
+
+ protected:
+  // The underlying type can only be integral, so we just need to check for
+  // referenced type.
+  std::unique_ptr<std::pair<std::string, std::string>> underlying_type_diff_;
+  std::vector<const EnumFieldIR *> fields_removed_;
+  std::vector<const EnumFieldIR *> fields_added_;
+  std::vector<EnumFieldDiffIR> fields_diff_;
+  // Modifiable to allow implicit construction.
+  std::string name_;
+};
+
+class GlobalVarDiffIR : public DiffMessageIR {
+ public:
+  LinkableMessageKind Kind() const override {
+    return LinkableMessageKind::GlobalVarKind;
+  }
+
+ GlobalVarDiffIR(const GlobalVarIR *old_global_var,
+                 const GlobalVarIR *new_global_var)
+      : old_global_var_(old_global_var), new_global_var_(new_global_var) { }
+
+ const GlobalVarIR *GetOldGlobalVar() const {
+   return old_global_var_;
+ }
+
+ const GlobalVarIR *GetNewGlobalVar() const {
+   return new_global_var_;
+ }
+
+ protected:
+  const GlobalVarIR *old_global_var_;
+  const GlobalVarIR *new_global_var_;
+};
+
+class FunctionDiffIR : public DiffMessageIR {
+ public:
+  LinkableMessageKind Kind() const override {
+    return LinkableMessageKind::FunctionKind;
+  }
+
+  FunctionDiffIR(const FunctionIR *old_function,
+                 const FunctionIR *new_function)
+      : old_function_(old_function), new_function_(new_function) { }
+
+  const FunctionIR *GetOldFunction() const {
+    return old_function_;
+  }
+
+  const FunctionIR *GetNewFunction() const {
+    return new_function_;
+  }
+
+ protected:
+  const FunctionIR *old_function_;
+  const FunctionIR *new_function_;
+};
+
+class IRDiffDumper {
+ public:
+  enum DiffKind {
+    Extension, // Applicable for enums.
+    Added,
+    Removed,
+    Referenced,
+    Unreferenced
+  };
+
+  IRDiffDumper(const std::string &dump_path) : dump_path_(dump_path) { }
+
+  virtual bool AddDiffMessageIR(const DiffMessageIR *,
+                                const std::string &type_stack,
+                                DiffKind diff_kind) = 0;
+
+  virtual bool AddLinkableMessageIR(const LinkableMessageIR *,
+                                    DiffKind diff_kind) = 0;
+
+  virtual bool AddElfSymbolMessageIR(const ElfSymbolIR *,
+                                     DiffKind diff_kind) = 0;
+
+  virtual void AddLibNameIR(const std::string &name) = 0;
+
+  virtual void AddArchIR(const std::string &arch) = 0;
+
+  virtual void AddCompatibilityStatusIR(CompatibilityStatusIR status) = 0;
+
+  virtual bool Dump() = 0;
+
+  virtual CompatibilityStatusIR GetCompatibilityStatusIR() = 0;
+
+  virtual ~IRDiffDumper() {}
+  static std::unique_ptr<IRDiffDumper> CreateIRDiffDumper(
+      const std::string &type, const std::string &dump_path);
+ protected:
+  const std::string &dump_path_;
+};
+
+} // namespace abi_util
+
+#endif // IR_
diff --git a/vndk/tools/header-checker/header-abi-util/include/ir_representation_protobuf.h b/vndk/tools/header-checker/header-abi-util/include/ir_representation_protobuf.h
new file mode 100644
index 0000000..e5cf61e
--- /dev/null
+++ b/vndk/tools/header-checker/header-abi-util/include/ir_representation_protobuf.h
@@ -0,0 +1,418 @@
+// 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 IR_PROTOBUF_
+#define IR_PROTOBUF_
+
+#include <ir_representation.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+#include "proto/abi_dump.pb.h"
+#include "proto/abi_diff.pb.h"
+#pragma clang diagnostic pop
+
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+
+// Classes which act as middle-men between clang AST parsing routines and
+// message format specific dumpers.
+namespace abi_util {
+
+inline abi_diff::CompatibilityStatus CompatibilityStatusIRToProtobuf(
+    CompatibilityStatusIR status) {
+  switch(status) {
+    case CompatibilityStatusIR::Incompatible:
+      return abi_diff::CompatibilityStatus::INCOMPATIBLE;
+    case CompatibilityStatusIR::Extension:
+      return abi_diff::CompatibilityStatus::EXTENSION;
+    default:
+      break;
+  }
+  return abi_diff::CompatibilityStatus::COMPATIBLE;
+}
+
+inline abi_dump::AccessSpecifier AccessIRToProtobuf(AccessSpecifierIR access) {
+  switch (access) {
+    case AccessSpecifierIR::ProtectedAccess:
+      return abi_dump::AccessSpecifier::protected_access;
+    case AccessSpecifierIR::PrivateAccess:
+      return abi_dump::AccessSpecifier::private_access;
+    default:
+      return abi_dump::AccessSpecifier::public_access;
+  }
+  return abi_dump::AccessSpecifier::public_access;
+}
+
+inline AccessSpecifierIR AccessProtobufToIR(
+    abi_dump::AccessSpecifier access) {
+  switch (access) {
+    case abi_dump::AccessSpecifier::protected_access:
+      return AccessSpecifierIR::ProtectedAccess;
+    case abi_dump::AccessSpecifier::private_access:
+      return AccessSpecifierIR::PrivateAccess;
+    default:
+      return AccessSpecifierIR::PublicAccess;
+  }
+  return AccessSpecifierIR::PublicAccess;
+}
+
+inline abi_dump::RecordKind RecordKindIRToProtobuf(
+    RecordTypeIR::RecordKind kind) {
+  switch (kind) {
+    case RecordTypeIR::RecordKind::struct_kind:
+      return abi_dump::RecordKind::struct_kind;
+
+    case RecordTypeIR::RecordKind::class_kind:
+      return abi_dump::RecordKind::class_kind;
+
+    case RecordTypeIR::RecordKind::union_kind:
+      return abi_dump::RecordKind::union_kind;
+
+    default:
+      return abi_dump::RecordKind::struct_kind;
+  }
+  // Should not be reached
+  assert(false);
+}
+
+inline abi_dump::VTableComponent::Kind VTableComponentKindIRToProtobuf(
+    VTableComponentIR::Kind kind) {
+  switch (kind) {
+    case VTableComponentIR::Kind::VCallOffset:
+      return abi_dump::VTableComponent_Kind_VCallOffset;
+
+    case VTableComponentIR::Kind::VBaseOffset:
+      return abi_dump::VTableComponent_Kind_VBaseOffset;
+
+    case VTableComponentIR::Kind::OffsetToTop:
+      return abi_dump::VTableComponent_Kind_OffsetToTop;
+
+    case VTableComponentIR::Kind::RTTI:
+      return abi_dump::VTableComponent_Kind_RTTI;
+
+    case VTableComponentIR::Kind::FunctionPointer:
+      return abi_dump::VTableComponent_Kind_FunctionPointer;
+
+    case VTableComponentIR::Kind::CompleteDtorPointer:
+      return abi_dump::VTableComponent_Kind_CompleteDtorPointer;
+
+    case VTableComponentIR::Kind::DeletingDtorPointer:
+      return abi_dump::VTableComponent_Kind_DeletingDtorPointer;
+
+    default:
+      return abi_dump::VTableComponent_Kind_UnusedFunctionPointer;
+  }
+  // Should not be reached
+  assert(false);
+}
+
+inline VTableComponentIR::Kind VTableComponentKindProtobufToIR(
+    abi_dump::VTableComponent_Kind kind) {
+  switch (kind) {
+    case abi_dump::VTableComponent_Kind_VCallOffset:
+      return VTableComponentIR::Kind::VCallOffset;
+
+    case abi_dump::VTableComponent_Kind_VBaseOffset:
+      return VTableComponentIR::Kind::VBaseOffset;
+
+    case abi_dump::VTableComponent_Kind_OffsetToTop:
+      return VTableComponentIR::Kind::OffsetToTop;
+
+    case abi_dump::VTableComponent_Kind_RTTI:
+      return VTableComponentIR::Kind::RTTI;
+
+    case abi_dump::VTableComponent_Kind_FunctionPointer:
+      return VTableComponentIR::Kind::FunctionPointer;
+
+    case abi_dump::VTableComponent_Kind_CompleteDtorPointer:
+      return VTableComponentIR::Kind::CompleteDtorPointer;
+
+    case abi_dump::VTableComponent_Kind_DeletingDtorPointer:
+      return VTableComponentIR::Kind::DeletingDtorPointer;
+
+    default:
+      return VTableComponentIR::Kind::UnusedFunctionPointer;
+  }
+  // Should not be reached
+  assert(false);
+}
+
+class IRToProtobufConverter {
+ private:
+  static bool AddTemplateInformation(
+    abi_dump::TemplateInfo *ti, const abi_util::TemplatedArtifactIR *ta);
+
+  static bool AddTypeInfo(
+      abi_dump::BasicNamedAndTypedDecl *type_info, const TypeIR *typep);
+
+  static bool AddRecordFields(
+      abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir);
+
+  static bool AddBaseSpecifiers(
+      abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir);
+
+  static bool AddVTableLayout(
+      abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir);
+
+  static bool AddEnumFields(abi_dump::EnumType *enum_protobuf,
+                            const EnumTypeIR *enum_ir);
+ public:
+  static abi_dump::EnumType ConvertEnumTypeIR(const EnumTypeIR *enump);
+
+  static abi_dump::RecordType ConvertRecordTypeIR(const RecordTypeIR *recordp);
+
+  static bool AddFunctionParameters(abi_dump::FunctionDecl *function_protobuf,
+                                    const FunctionIR *function_ir);
+
+  static abi_dump::FunctionDecl ConvertFunctionIR(const FunctionIR *functionp);
+
+  static abi_dump::GlobalVarDecl ConvertGlobalVarIR(
+      const GlobalVarIR *global_varp);
+
+  static abi_dump::PointerType ConvertPointerTypeIR(
+      const PointerTypeIR *pointerp);
+
+  static abi_dump::QualifiedType ConvertQualifiedTypeIR(
+      const QualifiedTypeIR *qualtypep);
+
+  static abi_dump::BuiltinType ConvertBuiltinTypeIR(
+      const BuiltinTypeIR *builtin_typep);
+
+  static abi_dump::ArrayType ConvertArrayTypeIR(
+      const ArrayTypeIR *array_typep);
+
+  static abi_dump::LvalueReferenceType ConvertLvalueReferenceTypeIR(
+      const LvalueReferenceTypeIR *lvalue_reference_typep);
+
+  static abi_dump::RvalueReferenceType ConvertRvalueReferenceTypeIR(
+      const RvalueReferenceTypeIR *rvalue_reference_typep);
+
+  static abi_dump::ElfFunction ConvertElfFunctionIR(
+      const ElfFunctionIR *elf_function_ir);
+
+  static abi_dump::ElfObject ConvertElfObjectIR(
+      const ElfObjectIR *elf_object_ir);
+};
+
+class IRDiffToProtobufConverter {
+ private:
+  static bool AddTypeInfoDiff(abi_diff::TypeInfoDiff *type_info_diff_protobuf,
+                              const TypeDiffIR *type_diff_ir);
+
+  static bool AddVTableLayoutDiff(
+    abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf,
+    const VTableLayoutDiffIR *vtable_layout_diff_ir);
+
+  static bool AddBaseSpecifierDiffs(
+    abi_diff::CXXBaseSpecifierDiff *base_specifier_diff_protobuf,
+    const CXXBaseSpecifierDiffIR *base_specifier_diff_ir);
+
+  static bool AddRecordFieldsRemoved(
+    abi_diff::RecordTypeDiff *record_diff_protobuf,
+    const std::vector<const RecordFieldIR *> &record_fields_removed_ir);
+
+  static bool AddRecordFieldDiffs(
+    abi_diff::RecordTypeDiff *record_diff_protobuf,
+    const std::vector<RecordFieldDiffIR> &record_field_diff_ir);
+
+  static bool AddEnumUnderlyingTypeDiff(
+    abi_diff::UnderlyingTypeDiff *underlying_type_diff_protobuf,
+    const std::pair<std::string, std::string> *underlying_type_diff_ir);
+
+ public:
+  static abi_diff::RecordTypeDiff ConvertRecordTypeDiffIR(
+      const RecordTypeDiffIR *record_type_diffp);
+
+  static abi_diff::EnumTypeDiff ConvertEnumTypeDiffIR(
+      const EnumTypeDiffIR *enum_type_diffp);
+
+  static abi_diff::FunctionDeclDiff ConvertFunctionDiffIR(
+      const FunctionDiffIR *function_diffp);
+
+  static abi_diff::GlobalVarDeclDiff ConvertGlobalVarDiffIR(
+      const GlobalVarDiffIR *global_var_diffp);
+};
+
+class ProtobufIRDumper : public IRDumper, public IRToProtobufConverter {
+ private:
+  // Types
+  bool AddRecordTypeIR(const RecordTypeIR *);
+
+  bool AddEnumTypeIR(const EnumTypeIR *);
+
+  bool AddPointerTypeIR(const PointerTypeIR *);
+
+  bool AddQualifiedTypeIR(const QualifiedTypeIR *);
+
+  bool AddLvalueReferenceTypeIR(const LvalueReferenceTypeIR *);
+
+  bool AddRvalueReferenceTypeIR(const RvalueReferenceTypeIR *);
+
+  bool AddArrayTypeIR(const ArrayTypeIR *);
+
+  bool AddBuiltinTypeIR(const BuiltinTypeIR *);
+
+  // Functions and global variables.
+  bool AddFunctionIR(const FunctionIR *);
+
+  bool AddGlobalVarIR(const GlobalVarIR *);
+
+ public:
+  ProtobufIRDumper(const std::string &dump_path)
+      : IRDumper(dump_path), tu_ptr_(new abi_dump::TranslationUnit()) { }
+
+  bool AddLinkableMessageIR(const LinkableMessageIR *);
+
+  bool Dump() override;
+
+  ~ProtobufIRDumper() override { }
+
+ private:
+  std::unique_ptr<abi_dump::TranslationUnit> tu_ptr_;
+};
+
+
+class ProtobufTextFormatToIRReader : public TextFormatToIRReader {
+ public:
+
+  virtual bool ReadDump() override;
+
+  ProtobufTextFormatToIRReader(const std::string &dump_path)
+      : TextFormatToIRReader(dump_path) { }
+
+ private:
+  std::vector<FunctionIR> ReadFunctions(
+       const abi_dump::TranslationUnit &tu);
+
+  std::vector<GlobalVarIR> ReadGlobalVariables(
+       const abi_dump::TranslationUnit &tu);
+
+  std::vector<EnumTypeIR> ReadEnumTypes(const abi_dump::TranslationUnit &tu);
+
+  std::vector<RecordTypeIR> ReadRecordTypes(
+      const abi_dump::TranslationUnit &tu);
+
+  std::vector<PointerTypeIR> ReadPointerTypes(
+       const abi_dump::TranslationUnit &tu);
+
+  std::vector<BuiltinTypeIR> ReadBuiltinTypes(
+       const abi_dump::TranslationUnit &tu);
+
+  std::vector<QualifiedTypeIR> ReadQualifiedTypes(
+       const abi_dump::TranslationUnit &tu);
+
+  std::vector<ArrayTypeIR> ReadArrayTypes(const abi_dump::TranslationUnit &tu);
+
+  std::vector<LvalueReferenceTypeIR> ReadLvalueReferenceTypes(
+       const abi_dump::TranslationUnit &tu);
+
+  std::vector<RvalueReferenceTypeIR> ReadRvalueReferenceTypes(
+       const abi_dump::TranslationUnit &tu);
+
+  std::vector<ElfFunctionIR> ReadElfFunctions (
+      const abi_dump::TranslationUnit &tu);
+
+  std::vector<ElfObjectIR> ReadElfObjects (const abi_dump::TranslationUnit &tu);
+
+  void ReadTypeInfo(const abi_dump::BasicNamedAndTypedDecl &type_info,
+                    TypeIR *typep);
+
+  FunctionIR FunctionProtobufToIR(const abi_dump::FunctionDecl &);
+
+  RecordTypeIR RecordTypeProtobufToIR(
+       const abi_dump::RecordType &record_type_protobuf);
+
+  std::vector<RecordFieldIR> RecordFieldsProtobufToIR(
+    const google::protobuf::RepeatedPtrField<abi_dump::RecordFieldDecl> &rfp);
+
+  std::vector<CXXBaseSpecifierIR> RecordCXXBaseSpecifiersProtobufToIR(
+    const google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> &rbs);
+
+  std::vector<EnumFieldIR> EnumFieldsProtobufToIR(
+       const google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> &efp);
+
+  EnumTypeIR EnumTypeProtobufToIR(
+       const abi_dump::EnumType &enum_type_protobuf);
+
+  VTableLayoutIR VTableLayoutProtobufToIR(
+    const abi_dump::VTableLayout &vtable_layout_protobuf);
+
+  TemplateInfoIR TemplateInfoProtobufToIR(
+       const abi_dump::TemplateInfo &template_info_protobuf);
+};
+
+class ProtobufIRDiffDumper : public IRDiffDumper {
+ public:
+  ProtobufIRDiffDumper(const std::string &dump_path)
+      : IRDiffDumper(dump_path),
+        diff_tu_(new abi_diff::TranslationUnitDiff()) { }
+
+  bool AddDiffMessageIR(const DiffMessageIR *, const std::string &type_stack,
+                        DiffKind diff_kind) override;
+
+  bool AddLinkableMessageIR(const LinkableMessageIR *,
+                            DiffKind diff_kind) override;
+
+  bool AddElfSymbolMessageIR(const ElfSymbolIR *, DiffKind diff_kind) override;
+
+  void AddLibNameIR(const std::string &name) override;
+
+  void AddArchIR(const std::string &arch) override;
+
+  void AddCompatibilityStatusIR(CompatibilityStatusIR status) override;
+
+  bool Dump() override;
+
+   CompatibilityStatusIR GetCompatibilityStatusIR() override;
+
+   ~ProtobufIRDiffDumper() override { }
+
+ private:
+  // User defined types.
+  bool AddRecordTypeDiffIR(const RecordTypeDiffIR *,
+                           const std::string &type_stack, DiffKind diff_kind);
+
+  bool AddEnumTypeDiffIR(const EnumTypeDiffIR *,
+                         const std::string &type_stack, DiffKind diff_kind);
+
+  // Functions and global variables.
+  bool AddFunctionDiffIR(const FunctionDiffIR *,
+                         const std::string &type_stack, DiffKind diff_kind);
+
+  bool AddGlobalVarDiffIR(const GlobalVarDiffIR *,
+                          const std::string &type_stack, DiffKind diff_kind);
+
+  bool AddLoneRecordTypeDiffIR(const RecordTypeIR *, DiffKind diff_kind);
+
+  bool AddLoneEnumTypeDiffIR(const EnumTypeIR *, DiffKind diff_kind);
+
+  // Functions and global variables.
+  bool AddLoneFunctionDiffIR(const FunctionIR *, DiffKind diff_kind);
+
+  bool AddLoneGlobalVarDiffIR(const GlobalVarIR *, DiffKind diff_kind);
+
+  bool AddElfObjectIR(const ElfObjectIR *elf_object_ir, DiffKind diff_kind);
+
+  bool AddElfFunctionIR(const ElfFunctionIR *elf_function_ir,
+                        DiffKind diff_kind);
+
+ protected:
+  std::unique_ptr<abi_diff::TranslationUnitDiff> diff_tu_;
+};
+
+} // abi_util
+
+#endif // IR_PROTOBUF_
diff --git a/vndk/tools/header-checker/header-abi-util/src/ir_representation.cpp b/vndk/tools/header-checker/header-abi-util/src/ir_representation.cpp
new file mode 100644
index 0000000..0cf58e1
--- /dev/null
+++ b/vndk/tools/header-checker/header-abi-util/src/ir_representation.cpp
@@ -0,0 +1,67 @@
+// 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 <ir_representation.h>
+#include <ir_representation_protobuf.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+#include "proto/abi_dump.pb.h"
+#pragma clang diagnostic pop
+
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+
+#include <llvm/Support/raw_ostream.h>
+
+#include <string>
+#include <memory>
+
+
+namespace abi_util {
+
+std::unique_ptr<IRDumper> IRDumper::CreateIRDumper(
+    const std::string &type, const std::string &dump_path) {
+  if (type == "protobuf") {
+    return std::make_unique<ProtobufIRDumper>(dump_path);
+  }
+  // Nothing else is supported yet.
+  llvm::errs() << type << " message format is not supported yet!\n";
+  return nullptr;
+}
+
+std::unique_ptr<IRDiffDumper> IRDiffDumper::CreateIRDiffDumper(
+    const std::string &type, const std::string &dump_path) {
+  if (type == "protobuf") {
+    return std::make_unique<ProtobufIRDiffDumper>(dump_path);
+  }
+  // Nothing else is supported yet.
+  llvm::errs() << type << " message format is not supported yet!\n";
+  return nullptr;
+}
+
+std::unique_ptr<TextFormatToIRReader>
+TextFormatToIRReader::CreateTextFormatToIRReader(
+    const std::string &type, const std::string &dump_path) {
+  if (type == "protobuf") {
+    return std::make_unique<ProtobufTextFormatToIRReader>(dump_path);
+  }
+  // Nothing else is supported yet.
+  llvm::errs() << type << " message format is not supported yet!\n";
+  return nullptr;
+}
+
+} // namespace abi_util
+
diff --git a/vndk/tools/header-checker/header-abi-util/src/ir_representation_protobuf.cpp b/vndk/tools/header-checker/header-abi-util/src/ir_representation_protobuf.cpp
new file mode 100644
index 0000000..f3958d8
--- /dev/null
+++ b/vndk/tools/header-checker/header-abi-util/src/ir_representation_protobuf.cpp
@@ -0,0 +1,1353 @@
+// 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 <ir_representation_protobuf.h>
+
+#include <llvm/Support/raw_ostream.h>
+
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <memory>
+
+namespace abi_util {
+
+void ProtobufTextFormatToIRReader::ReadTypeInfo(
+    const abi_dump::BasicNamedAndTypedDecl &type_info,
+    TypeIR *typep) {
+  typep->SetLinkerSetKey(type_info.linker_set_key());
+  typep->SetName(type_info.linker_set_key());
+  typep->SetSourceFile(type_info.source_file());
+  typep->SetReferencedType(type_info.referenced_type());
+  typep->SetSize(type_info.size());
+  typep->SetAlignment(type_info.alignment());
+}
+
+bool ProtobufTextFormatToIRReader::ReadDump() {
+  abi_dump::TranslationUnit tu;
+  std::ifstream input(dump_path_);
+  google::protobuf::io::IstreamInputStream text_is(&input);
+
+  if (!google::protobuf::TextFormat::Parse(&text_is, &tu)) {
+    llvm::errs() << "Failed to parse protobuf TextFormat file\n";
+    return false;
+  }
+
+  functions_ = ReadFunctions(tu);
+  global_variables_ = ReadGlobalVariables(tu);
+
+  enum_types_ = ReadEnumTypes(tu);
+  record_types_ = ReadRecordTypes(tu);
+  array_types_ = ReadArrayTypes(tu);
+  pointer_types_ = ReadPointerTypes(tu);
+  qualified_types_ = ReadQualifiedTypes(tu);
+  builtin_types_ = ReadBuiltinTypes(tu);
+  lvalue_reference_types_ = ReadLvalueReferenceTypes(tu);
+  rvalue_reference_types_ = ReadRvalueReferenceTypes(tu);
+
+  elf_functions_ = ReadElfFunctions(tu);
+  elf_objects_ = ReadElfObjects(tu);
+
+  return true;
+}
+
+TemplateInfoIR ProtobufTextFormatToIRReader::TemplateInfoProtobufToIR(
+    const abi_dump::TemplateInfo &template_info_protobuf) {
+  TemplateInfoIR template_info_ir;
+  for (auto &&template_element : template_info_protobuf.elements()) {
+    TemplateElementIR template_element_ir(template_element.referenced_type());
+    template_info_ir.AddTemplateElement(std::move(template_element_ir));
+  }
+  return template_info_ir;
+}
+
+FunctionIR ProtobufTextFormatToIRReader::FunctionProtobufToIR(
+    const abi_dump::FunctionDecl &function_protobuf) {
+  FunctionIR function_ir;
+  function_ir.SetReturnType(function_protobuf.return_type());
+  function_ir.SetLinkerSetKey(function_protobuf.linker_set_key());
+  function_ir.SetName(function_protobuf.function_name());
+  function_ir.SetAccess(AccessProtobufToIR(function_protobuf.access()));
+  function_ir.SetSourceFile(function_protobuf.source_file());
+  // Set parameters
+  for (auto &&parameter: function_protobuf.parameters()) {
+    ParamIR param_ir(parameter.referenced_type(), parameter.default_arg());
+    function_ir.AddParameter(std::move(param_ir));
+  }
+  // Set Template info
+  function_ir.SetTemplateInfo(
+      TemplateInfoProtobufToIR(function_protobuf.template_info()));
+  return function_ir;
+}
+
+VTableLayoutIR ProtobufTextFormatToIRReader::VTableLayoutProtobufToIR(
+    const abi_dump::VTableLayout &vtable_layout_protobuf) {
+  VTableLayoutIR vtable_layout_ir;
+  for (auto &&vtable_component : vtable_layout_protobuf.vtable_components()) {
+    VTableComponentIR vtable_component_ir(
+        vtable_component.mangled_component_name(),
+        VTableComponentKindProtobufToIR(vtable_component.kind()),
+        vtable_component.component_value());
+    vtable_layout_ir.AddVTableComponent(std::move(vtable_component_ir));
+  }
+  return vtable_layout_ir;
+}
+
+std::vector<RecordFieldIR>
+ProtobufTextFormatToIRReader::RecordFieldsProtobufToIR(
+    const google::protobuf::RepeatedPtrField<abi_dump::RecordFieldDecl> &rfp) {
+  std::vector<RecordFieldIR> record_type_fields_ir;
+  for (auto &&field : rfp) {
+    RecordFieldIR record_field_ir(field.field_name(), field.referenced_type(),
+                                  field.field_offset(),
+                                  AccessProtobufToIR(field.access()));
+    record_type_fields_ir.emplace_back(std::move(record_field_ir));
+  }
+  return record_type_fields_ir;
+}
+
+std::vector<CXXBaseSpecifierIR>
+ProtobufTextFormatToIRReader::RecordCXXBaseSpecifiersProtobufToIR(
+    const google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> &rbs) {
+  std::vector<CXXBaseSpecifierIR> record_type_bases_ir;
+  for (auto &&base : rbs) {
+    CXXBaseSpecifierIR record_base_ir(
+        base.referenced_type(), base.is_virtual(),
+        AccessProtobufToIR(base.access()));
+    record_type_bases_ir.emplace_back(std::move(record_base_ir));
+  }
+  return record_type_bases_ir;
+}
+
+RecordTypeIR ProtobufTextFormatToIRReader::RecordTypeProtobufToIR(
+    const abi_dump::RecordType &record_type_protobuf) {
+  RecordTypeIR record_type_ir;
+  ReadTypeInfo(record_type_protobuf.type_info(), &record_type_ir);
+  record_type_ir.SetTemplateInfo(
+      TemplateInfoProtobufToIR(record_type_protobuf.template_info()));
+  record_type_ir.SetAccess(AccessProtobufToIR(record_type_protobuf.access()));
+  record_type_ir.SetVTableLayout(
+      VTableLayoutProtobufToIR(record_type_protobuf.vtable_layout()));
+  // Get fields
+  record_type_ir.SetRecordFields(RecordFieldsProtobufToIR(
+      record_type_protobuf.fields()));
+  // Base Specifiers
+  record_type_ir.SetCXXBaseSpecifiers(RecordCXXBaseSpecifiersProtobufToIR(
+      record_type_protobuf.base_specifiers()));
+
+  return record_type_ir;
+}
+
+std::vector<EnumFieldIR>
+ProtobufTextFormatToIRReader::EnumFieldsProtobufToIR(
+    const google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> &efp) {
+  std::vector<EnumFieldIR> enum_type_fields_ir;
+  for (auto &&field : efp) {
+    EnumFieldIR enum_field_ir(field.name(), field.enum_field_value());
+    enum_type_fields_ir.emplace_back(std::move(enum_field_ir));
+  }
+  return enum_type_fields_ir;
+}
+
+EnumTypeIR ProtobufTextFormatToIRReader::EnumTypeProtobufToIR(
+    const abi_dump::EnumType &enum_type_protobuf) {
+  EnumTypeIR enum_type_ir;
+  ReadTypeInfo(enum_type_protobuf.type_info(), &enum_type_ir);
+  enum_type_ir.SetUnderlyingType(enum_type_protobuf.underlying_type());
+  enum_type_ir.SetAccess(AccessProtobufToIR(enum_type_protobuf.access()));
+  enum_type_ir.SetFields(
+      EnumFieldsProtobufToIR(enum_type_protobuf.enum_fields()));
+  return enum_type_ir;
+}
+
+std::vector<GlobalVarIR> ProtobufTextFormatToIRReader::ReadGlobalVariables(
+    const abi_dump::TranslationUnit &tu) {
+  std::vector<GlobalVarIR> global_variables;
+  for (auto &&global_variable_protobuf : tu.global_vars()) {
+    GlobalVarIR global_variable_ir;
+    global_variable_ir.SetName(global_variable_protobuf.name());
+    global_variable_ir.SetSourceFile(global_variable_protobuf.source_file());
+    global_variable_ir.SetReferencedType(
+        global_variable_protobuf.referenced_type());
+    global_variable_ir.SetLinkerSetKey(
+        global_variable_protobuf.linker_set_key());
+    global_variables.emplace_back(std::move(global_variable_ir));
+  }
+  return global_variables;
+}
+
+std::vector<PointerTypeIR> ProtobufTextFormatToIRReader::ReadPointerTypes(
+    const abi_dump::TranslationUnit &tu) {
+  std::vector<PointerTypeIR> pointer_types;
+  for (auto &&pointer_type_protobuf : tu.pointer_types()) {
+    PointerTypeIR pointer_type_ir;
+    ReadTypeInfo(pointer_type_protobuf.type_info(), &pointer_type_ir);
+    pointer_types.emplace_back(std::move(pointer_type_ir));
+  }
+  return pointer_types;
+}
+
+std::vector<BuiltinTypeIR> ProtobufTextFormatToIRReader::ReadBuiltinTypes(
+    const abi_dump::TranslationUnit &tu) {
+  std::vector<BuiltinTypeIR> builtin_types;
+  for (auto &&builtin_type_protobuf : tu.builtin_types()) {
+    BuiltinTypeIR builtin_type_ir;
+    ReadTypeInfo(builtin_type_protobuf.type_info(), &builtin_type_ir);
+    builtin_type_ir.SetSignedness(builtin_type_protobuf.is_unsigned());
+    builtin_type_ir.SetIntegralType(builtin_type_protobuf.is_integral());
+    builtin_types.emplace_back(std::move(builtin_type_ir));
+  }
+  return builtin_types;
+}
+
+std::vector<QualifiedTypeIR> ProtobufTextFormatToIRReader::ReadQualifiedTypes(
+    const abi_dump::TranslationUnit &tu) {
+  std::vector<QualifiedTypeIR> qualified_types;
+  for (auto &&qualified_type_protobuf : tu.qualified_types()) {
+    QualifiedTypeIR qualified_type_ir;
+    ReadTypeInfo(qualified_type_protobuf.type_info(), &qualified_type_ir);
+    qualified_types.emplace_back(std::move(qualified_type_ir));
+  }
+  return qualified_types;
+}
+
+std::vector<ArrayTypeIR> ProtobufTextFormatToIRReader::ReadArrayTypes(
+    const abi_dump::TranslationUnit &tu) {
+  std::vector<ArrayTypeIR> array_types;
+  for (auto &&array_type_protobuf : tu.array_types()) {
+    ArrayTypeIR array_type_ir;
+    ReadTypeInfo(array_type_protobuf.type_info(), &array_type_ir);
+    array_types.emplace_back(std::move(array_type_ir));
+  }
+  return array_types;
+}
+
+std::vector<LvalueReferenceTypeIR>
+ProtobufTextFormatToIRReader::ReadLvalueReferenceTypes(
+    const abi_dump::TranslationUnit &tu) {
+  std::vector<LvalueReferenceTypeIR> lvalue_reference_types;
+  for (auto &&lvalue_reference_type_protobuf : tu.lvalue_reference_types()) {
+    LvalueReferenceTypeIR lvalue_reference_type_ir;
+    ReadTypeInfo(lvalue_reference_type_protobuf.type_info(),
+                 &lvalue_reference_type_ir);
+    lvalue_reference_types.emplace_back(std::move(lvalue_reference_type_ir));
+  }
+  return lvalue_reference_types;
+}
+
+std::vector<RvalueReferenceTypeIR>
+ProtobufTextFormatToIRReader::ReadRvalueReferenceTypes(
+    const abi_dump::TranslationUnit &tu) {
+  std::vector<RvalueReferenceTypeIR> rvalue_reference_types;
+  for (auto &&rvalue_reference_type_protobuf : tu.rvalue_reference_types()) {
+    RvalueReferenceTypeIR rvalue_reference_type_ir;
+    ReadTypeInfo(rvalue_reference_type_protobuf.type_info(),
+                 &rvalue_reference_type_ir);
+    rvalue_reference_types.emplace_back(std::move(rvalue_reference_type_ir));
+  }
+  return rvalue_reference_types;
+}
+
+std::vector<FunctionIR> ProtobufTextFormatToIRReader::ReadFunctions(
+    const abi_dump::TranslationUnit &tu) {
+  std::vector<FunctionIR> functions;
+  for (auto &&function_protobuf : tu.functions()) {
+    FunctionIR function_ir = FunctionProtobufToIR(function_protobuf);
+    functions.emplace_back(std::move(function_ir));
+  }
+  return functions;
+}
+
+std::vector<RecordTypeIR> ProtobufTextFormatToIRReader::ReadRecordTypes(
+    const abi_dump::TranslationUnit &tu) {
+  std::vector<RecordTypeIR> record_types;
+  for (auto &&record_type_protobuf : tu.record_types()) {
+    RecordTypeIR record_type_ir = RecordTypeProtobufToIR(record_type_protobuf);
+    record_types.emplace_back(std::move(record_type_ir));
+  }
+  return record_types;
+}
+
+std::vector<EnumTypeIR> ProtobufTextFormatToIRReader::ReadEnumTypes(
+    const abi_dump::TranslationUnit &tu) {
+  std::vector<EnumTypeIR> enum_types;
+  for (auto &&enum_type_protobuf : tu.enum_types()) {
+    EnumTypeIR enum_type_ir = EnumTypeProtobufToIR(enum_type_protobuf);
+    enum_types.emplace_back(std::move(enum_type_ir));
+  }
+  return enum_types;
+}
+
+std::vector<ElfFunctionIR> ProtobufTextFormatToIRReader::ReadElfFunctions(
+    const abi_dump::TranslationUnit &tu) {
+  std::vector<ElfFunctionIR> elf_functions;
+  for (auto &&elf_function : tu.elf_functions()) {
+    elf_functions.emplace_back(ElfFunctionIR(elf_function.name()));
+  }
+  return elf_functions;
+}
+
+std::vector<ElfObjectIR> ProtobufTextFormatToIRReader::ReadElfObjects(
+    const abi_dump::TranslationUnit &tu) {
+  std::vector<ElfObjectIR> elf_objects;
+  for (auto &&elf_object : tu.elf_objects()) {
+    elf_objects.emplace_back(ElfObjectIR(elf_object.name()));
+  }
+  return elf_objects;
+}
+
+bool IRToProtobufConverter::AddTemplateInformation(
+    abi_dump::TemplateInfo *ti, const abi_util::TemplatedArtifactIR *ta) {
+  for (auto &&template_element : ta->GetTemplateElements()) {
+    abi_dump::TemplateElement *added_element = ti->add_elements();
+    if (!added_element) {
+      llvm::errs() << "Failed to add template element\n";
+      return false;
+    }
+    added_element->set_referenced_type(template_element.GetReferencedType());
+  }
+  return true;
+}
+
+bool IRToProtobufConverter::AddTypeInfo(
+    abi_dump::BasicNamedAndTypedDecl *type_info,
+    const TypeIR *typep) {
+  if (!type_info || !typep) {
+    llvm::errs() << "Typeinfo not valid\n";
+    return false;
+  }
+  type_info->set_linker_set_key(typep->GetLinkerSetKey());
+  type_info->set_source_file(typep->GetSourceFile());
+  type_info->set_name(typep->GetName());
+  type_info->set_size(typep->GetSize());
+  type_info->set_alignment(typep->GetAlignment());
+  type_info->set_referenced_type(typep->GetReferencedType());
+  return true;
+}
+
+static void SetIRToProtobufRecordField(
+    abi_dump::RecordFieldDecl *record_field_protobuf,
+    const RecordFieldIR *record_field_ir) {
+  record_field_protobuf->set_field_name(record_field_ir->GetName());
+  record_field_protobuf->set_referenced_type(
+      record_field_ir->GetReferencedType());
+  record_field_protobuf->set_access(
+      AccessIRToProtobuf(record_field_ir->GetAccess()));
+  record_field_protobuf->set_field_offset(record_field_ir->GetOffset());
+}
+
+bool IRToProtobufConverter::AddRecordFields(
+    abi_dump::RecordType *record_protobuf,
+    const RecordTypeIR *record_ir) {
+  // Iterate through the fields and create corresponding ones for the protobuf
+  // record
+  for (auto &&field_ir : record_ir->GetFields()) {
+    abi_dump::RecordFieldDecl *added_field = record_protobuf->add_fields();
+    if (!added_field) {
+      llvm::errs() << "Couldn't add record field\n";
+    }
+    SetIRToProtobufRecordField(added_field, &field_ir);
+  }
+  return true;
+}
+
+static bool SetIRToProtobufBaseSpecifier(
+    abi_dump::CXXBaseSpecifier *base_specifier_protobuf,
+    const CXXBaseSpecifierIR &base_specifier_ir) {
+  if (!base_specifier_protobuf) {
+    llvm::errs() << "Protobuf base specifier not valid\n";
+    return false;
+  }
+  base_specifier_protobuf->set_referenced_type(
+      base_specifier_ir.GetReferencedType());
+  base_specifier_protobuf->set_is_virtual(
+      base_specifier_ir.IsVirtual());
+  base_specifier_protobuf->set_access(
+      AccessIRToProtobuf(base_specifier_ir.GetAccess()));
+  return true;
+}
+
+bool IRToProtobufConverter::AddBaseSpecifiers(
+    abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir) {
+  for (auto &&base_ir : record_ir->GetBases()) {
+    abi_dump::CXXBaseSpecifier *added_base =
+        record_protobuf->add_base_specifiers();
+    if (!SetIRToProtobufBaseSpecifier(added_base, base_ir)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+static bool SetIRToProtobufVTableLayout(
+    abi_dump::VTableLayout *vtable_layout_protobuf,
+    const VTableLayoutIR &vtable_layout_ir) {
+  if (vtable_layout_protobuf == nullptr) {
+    llvm::errs() << "vtable layout protobuf not valid\n";
+    return false;
+  }
+  for (auto &&vtable_component_ir : vtable_layout_ir.GetVTableComponents()) {
+    abi_dump::VTableComponent *added_vtable_component =
+        vtable_layout_protobuf->add_vtable_components();
+    if (!added_vtable_component) {
+      llvm::errs() << "Couldn't add vtable component\n";
+      return false;
+    }
+    added_vtable_component->set_kind(
+        VTableComponentKindIRToProtobuf(vtable_component_ir.GetKind()));
+    added_vtable_component->set_component_value(vtable_component_ir.GetValue());
+    added_vtable_component->set_mangled_component_name(
+        vtable_component_ir.GetName());
+  }
+  return true;
+}
+
+bool IRToProtobufConverter::AddVTableLayout(
+    abi_dump::RecordType *record_protobuf,
+    const RecordTypeIR *record_ir) {
+  // If there are no entries in the vtable, just return.
+  if (record_ir->GetVTableNumEntries() == 0) {
+    return true;
+  }
+  const VTableLayoutIR &vtable_layout_ir = record_ir->GetVTableLayout();
+  abi_dump::VTableLayout *vtable_layout_protobuf =
+      record_protobuf->mutable_vtable_layout();
+  if (!SetIRToProtobufVTableLayout(vtable_layout_protobuf, vtable_layout_ir)) {
+    return false;
+  }
+  return true;
+}
+
+abi_dump::RecordType IRToProtobufConverter::ConvertRecordTypeIR(
+    const RecordTypeIR *recordp) {
+  abi_dump::RecordType added_record_type;
+  added_record_type.set_access(AccessIRToProtobuf(recordp->GetAccess()));
+  added_record_type.set_record_kind(
+      RecordKindIRToProtobuf(recordp->GetRecordKind()));
+  if (recordp->IsAnonymous()) {
+    added_record_type.set_is_anonymous(true);
+  }
+  if (!AddTypeInfo(added_record_type.mutable_type_info(), recordp) ||
+      !AddRecordFields(&added_record_type, recordp) ||
+      !AddBaseSpecifiers(&added_record_type, recordp) ||
+      !AddVTableLayout(&added_record_type, recordp) ||
+      !(recordp->GetTemplateElements().size() ?
+       AddTemplateInformation(added_record_type.mutable_template_info(),
+                              recordp) : true)) {
+    llvm::errs() << "Template information could not be added\n";
+    ::exit(1);
+  }
+  return added_record_type;
+}
+
+
+abi_dump::ElfObject IRToProtobufConverter::ConvertElfObjectIR(
+    const ElfObjectIR *elf_object_ir) {
+  abi_dump::ElfObject elf_object_protobuf;
+  elf_object_protobuf.set_name(elf_object_ir->GetName());
+  return elf_object_protobuf;
+}
+
+abi_dump::ElfFunction IRToProtobufConverter::ConvertElfFunctionIR(
+    const ElfFunctionIR *elf_function_ir) {
+  abi_dump::ElfFunction elf_function_protobuf;
+  elf_function_protobuf.set_name(elf_function_ir->GetName());
+  return elf_function_protobuf;
+}
+
+bool IRToProtobufConverter::AddFunctionParameters(
+    abi_dump::FunctionDecl *function_protobuf,
+    const FunctionIR *function_ir) {
+  for (auto &&parameter : function_ir->GetParameters()) {
+    abi_dump::ParamDecl *added_parameter = function_protobuf->add_parameters();
+    if (!added_parameter) {
+      return false;
+    }
+    added_parameter->set_referenced_type(
+        parameter.GetReferencedType());
+    added_parameter->set_default_arg(parameter.GetIsDefault());
+  }
+  return true;
+}
+
+abi_dump::FunctionDecl IRToProtobufConverter::ConvertFunctionIR(
+    const FunctionIR *functionp) {
+  abi_dump::FunctionDecl added_function;
+  added_function.set_access(AccessIRToProtobuf(functionp->GetAccess()));
+  added_function.set_linker_set_key(functionp->GetLinkerSetKey());
+  added_function.set_source_file(functionp->GetSourceFile());
+  added_function.set_function_name(functionp->GetName());
+  added_function.set_return_type(functionp->GetReturnType());
+  if (!AddFunctionParameters(&added_function, functionp) ||
+      !(functionp->GetTemplateElements().size() ?
+      AddTemplateInformation(added_function.mutable_template_info(), functionp)
+      : true)) {
+    llvm::errs() << "Template information could not be added\n";
+    ::exit(1);
+  }
+  return added_function;
+}
+
+static bool SetIRToProtobufEnumField(
+    abi_dump::EnumFieldDecl *enum_field_protobuf,
+    const EnumFieldIR *enum_field_ir) {
+  if (enum_field_protobuf == nullptr) {
+    return true;
+  }
+  enum_field_protobuf->set_name(enum_field_ir->GetName());
+  enum_field_protobuf->set_enum_field_value(enum_field_ir->GetValue());
+  return true;
+}
+
+bool IRToProtobufConverter::AddEnumFields(abi_dump::EnumType *enum_protobuf,
+                                     const EnumTypeIR *enum_ir) {
+  for (auto &&field : enum_ir->GetFields()) {
+    abi_dump::EnumFieldDecl *enum_fieldp = enum_protobuf->add_enum_fields();
+    if (!SetIRToProtobufEnumField(enum_fieldp, &field)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+abi_dump::EnumType IRToProtobufConverter::ConvertEnumTypeIR(
+    const EnumTypeIR *enump) {
+  abi_dump::EnumType added_enum_type;
+  added_enum_type.set_access(AccessIRToProtobuf(enump->GetAccess()));
+  added_enum_type.set_underlying_type(enump->GetUnderlyingType());
+  if (!AddTypeInfo(added_enum_type.mutable_type_info(), enump) ||
+      !AddEnumFields(&added_enum_type, enump)) {
+    llvm::errs() << "EnumTypeIR could not be converted\n";
+    ::exit(1);
+  }
+  return added_enum_type;
+}
+
+abi_dump::GlobalVarDecl IRToProtobufConverter::ConvertGlobalVarIR(
+    const GlobalVarIR *global_varp) {
+  abi_dump::GlobalVarDecl added_global_var;
+  added_global_var.set_referenced_type(global_varp->GetReferencedType());
+  added_global_var.set_source_file(global_varp->GetSourceFile());
+  added_global_var.set_name(global_varp->GetName());
+  added_global_var.set_linker_set_key(global_varp->GetLinkerSetKey());
+  added_global_var.set_access(
+      AccessIRToProtobuf(global_varp->GetAccess()));
+  return added_global_var;
+}
+
+abi_dump::PointerType IRToProtobufConverter::ConvertPointerTypeIR(
+    const PointerTypeIR *pointerp) {
+  abi_dump::PointerType added_pointer_type;
+  if (!AddTypeInfo(added_pointer_type.mutable_type_info(), pointerp)) {
+    llvm::errs() << "PointerTypeIR could not be converted\n";
+    ::exit(1);
+  }
+  return added_pointer_type;
+}
+
+abi_dump::QualifiedType IRToProtobufConverter::ConvertQualifiedTypeIR(
+    const QualifiedTypeIR *qualtypep) {
+  abi_dump::QualifiedType added_qualified_type;
+  if (!AddTypeInfo(added_qualified_type.mutable_type_info(), qualtypep)) {
+    llvm::errs() << "QualifiedTypeIR could not be converted\n";
+    ::exit(1);
+  }
+  added_qualified_type.set_is_const(qualtypep->IsConst());
+  added_qualified_type.set_is_volatile(qualtypep->IsVolatile());
+  added_qualified_type.set_is_restricted(qualtypep->IsRestricted());
+  return added_qualified_type;
+}
+
+abi_dump::BuiltinType IRToProtobufConverter::ConvertBuiltinTypeIR(
+    const BuiltinTypeIR *builtin_typep) {
+  abi_dump::BuiltinType added_builtin_type;
+  added_builtin_type.set_is_unsigned(builtin_typep->IsUnsigned());
+  added_builtin_type.set_is_integral(builtin_typep->IsIntegralType());
+  if (!AddTypeInfo(added_builtin_type.mutable_type_info(), builtin_typep)) {
+    llvm::errs() << "BuiltinTypeIR could not be converted\n";
+    ::exit(1);
+  }
+  return added_builtin_type;
+}
+
+abi_dump::ArrayType IRToProtobufConverter::ConvertArrayTypeIR(
+    const ArrayTypeIR *array_typep) {
+  abi_dump::ArrayType added_array_type;
+  if (!AddTypeInfo(added_array_type.mutable_type_info(), array_typep)) {
+    llvm::errs() << "ArrayTypeIR could not be converted\n";
+    ::exit(1);
+  }
+  return added_array_type;
+}
+
+abi_dump::LvalueReferenceType
+IRToProtobufConverter::ConvertLvalueReferenceTypeIR(
+    const LvalueReferenceTypeIR *lvalue_reference_typep) {
+  abi_dump::LvalueReferenceType added_lvalue_reference_type;
+  if (!AddTypeInfo(added_lvalue_reference_type.mutable_type_info(),
+                   lvalue_reference_typep)) {
+    llvm::errs() << "LvalueReferenceTypeIR could not be converted\n";
+    ::exit(1);
+  }
+  return added_lvalue_reference_type;
+}
+
+abi_dump::RvalueReferenceType
+IRToProtobufConverter::ConvertRvalueReferenceTypeIR(
+    const RvalueReferenceTypeIR *rvalue_reference_typep) {
+  abi_dump::RvalueReferenceType added_rvalue_reference_type;
+  if (!AddTypeInfo(added_rvalue_reference_type.mutable_type_info(),
+                   rvalue_reference_typep)) {
+    llvm::errs() << "RvalueReferenceTypeIR could not be converted\n";
+    ::exit(1);
+  }
+  return added_rvalue_reference_type;
+}
+
+
+bool IRDiffToProtobufConverter::AddTypeInfoDiff(
+    abi_diff::TypeInfoDiff *type_info_diff_protobuf,
+    const TypeDiffIR *type_diff_ir) {
+  abi_diff::TypeInfo *old_type_info_protobuf =
+      type_info_diff_protobuf->mutable_old_type_info();
+  abi_diff::TypeInfo *new_type_info_protobuf =
+      type_info_diff_protobuf->mutable_new_type_info();
+  if (old_type_info_protobuf == nullptr || new_type_info_protobuf == nullptr) {
+    return false;
+  }
+  const std::pair<uint64_t, uint64_t> &sizes = type_diff_ir->GetSizes();
+  const std::pair<uint32_t, uint32_t> &alignments =
+      type_diff_ir->GetAlignments();
+  old_type_info_protobuf->set_size(sizes.first);
+  new_type_info_protobuf->set_size(sizes.second);
+
+  old_type_info_protobuf->set_alignment(alignments.first);
+  new_type_info_protobuf->set_alignment(alignments.second);
+  return true;
+}
+
+bool IRDiffToProtobufConverter::AddVTableLayoutDiff(
+    abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf,
+    const VTableLayoutDiffIR *vtable_layout_diff_ir) {
+  abi_dump:: VTableLayout *old_vtable =
+      vtable_layout_diff_protobuf->mutable_old_vtable();
+  abi_dump:: VTableLayout *new_vtable =
+      vtable_layout_diff_protobuf->mutable_new_vtable();
+  if (old_vtable == nullptr || new_vtable == nullptr ||
+      !SetIRToProtobufVTableLayout(old_vtable,
+                                   vtable_layout_diff_ir->GetOldVTable()) ||
+      !SetIRToProtobufVTableLayout(new_vtable,
+                                   vtable_layout_diff_ir->GetNewVTable())) {
+    return false;
+  }
+  return true;
+}
+
+template <typename T>
+static bool CopyBaseSpecifiersDiffIRToProtobuf(
+    google::protobuf::RepeatedPtrField<T> *dst,
+    const std::vector<CXXBaseSpecifierIR> &bases_ir) {
+  for (auto &&base_ir : bases_ir) {
+    T *added_base = dst->Add();
+    if (!SetIRToProtobufBaseSpecifier(added_base, base_ir)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool IRDiffToProtobufConverter::AddBaseSpecifierDiffs(
+    abi_diff::CXXBaseSpecifierDiff *base_specifiers_diff_protobuf,
+    const CXXBaseSpecifierDiffIR *base_specifiers_diff_ir) {
+  if (!CopyBaseSpecifiersDiffIRToProtobuf(
+          base_specifiers_diff_protobuf->mutable_old_bases(),
+          base_specifiers_diff_ir->GetOldBases()) ||
+      !CopyBaseSpecifiersDiffIRToProtobuf(
+          base_specifiers_diff_protobuf->mutable_new_bases(),
+          base_specifiers_diff_ir->GetNewBases())) {
+    return false;
+  }
+  return true;
+}
+
+bool IRDiffToProtobufConverter::AddRecordFieldsRemoved(
+    abi_diff::RecordTypeDiff *record_diff_protobuf,
+    const std::vector<const RecordFieldIR *> &record_fields_removed_ir) {
+  for (auto &&record_field_ir : record_fields_removed_ir) {
+    abi_dump::RecordFieldDecl *field_removed =
+        record_diff_protobuf->add_fields_removed();
+    if (field_removed == nullptr) {
+      return false;
+    }
+    SetIRToProtobufRecordField(field_removed, record_field_ir);
+  }
+  return true;
+}
+
+bool IRDiffToProtobufConverter::AddRecordFieldDiffs(
+    abi_diff::RecordTypeDiff *record_diff_protobuf,
+    const std::vector<RecordFieldDiffIR> &record_field_diffs_ir) {
+  for (auto &&record_field_diff_ir : record_field_diffs_ir) {
+    abi_diff::RecordFieldDeclDiff *record_field_diff =
+        record_diff_protobuf->add_fields_diff();
+    if (record_field_diff == nullptr) {
+      return false;
+    }
+    abi_dump::RecordFieldDecl *old_field =
+        record_field_diff->mutable_old_field();
+    abi_dump::RecordFieldDecl *new_field =
+        record_field_diff->mutable_new_field();
+    if (old_field == nullptr || new_field == nullptr) {
+      return false;
+    }
+    SetIRToProtobufRecordField(old_field,
+                               record_field_diff_ir.GetOldField());
+    SetIRToProtobufRecordField(new_field,
+                               record_field_diff_ir.GetNewField());
+  }
+  return true;
+}
+
+abi_diff::RecordTypeDiff IRDiffToProtobufConverter::ConvertRecordTypeDiffIR(
+    const RecordTypeDiffIR *record_type_diff_ir) {
+  abi_diff::RecordTypeDiff record_type_diff_protobuf;
+  record_type_diff_protobuf.set_name(record_type_diff_ir->GetName());
+  const TypeDiffIR *type_diff_ir = record_type_diff_ir->GetTypeDiff();
+  // If a type_info diff exists
+  if (type_diff_ir != nullptr) {
+    abi_diff::TypeInfoDiff *type_info_diff =
+        record_type_diff_protobuf.mutable_type_info_diff();
+    if (!AddTypeInfoDiff(type_info_diff, type_diff_ir)) {
+        llvm::errs() << "RecordType could not be converted\n";
+       ::exit(1);
+    }
+  }
+  // If vtables differ.
+  const VTableLayoutDiffIR *vtable_layout_diff_ir =
+      record_type_diff_ir->GetVTableLayoutDiff();
+  if (vtable_layout_diff_ir != nullptr) {
+    abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf =
+        record_type_diff_protobuf.mutable_vtable_layout_diff();
+    if (!AddVTableLayoutDiff(vtable_layout_diff_protobuf,
+                             vtable_layout_diff_ir)) {
+      llvm::errs() << "VTable layout diff could not be added\n";
+      ::exit(1);
+    }
+  }
+  // If base specifiers differ.
+  const CXXBaseSpecifierDiffIR *base_specifier_diff_ir =
+      record_type_diff_ir->GetBaseSpecifiers();
+  if ( base_specifier_diff_ir != nullptr) {
+    abi_diff::CXXBaseSpecifierDiff *base_specifier_diff_protobuf =
+        record_type_diff_protobuf.mutable_bases_diff();
+    if (!AddBaseSpecifierDiffs(base_specifier_diff_protobuf,
+                               base_specifier_diff_ir)) {
+      llvm::errs() << "Base Specifier diff could not be added\n";
+      ::exit(1);
+    }
+  }
+  // Field diffs
+  if (!AddRecordFieldsRemoved(&record_type_diff_protobuf,
+                               record_type_diff_ir->GetFieldsRemoved()) ||
+      !AddRecordFieldDiffs(&record_type_diff_protobuf,
+                            record_type_diff_ir->GetFieldDiffs())) {
+    llvm::errs() << "Record Field diff could not be added\n";
+    ::exit(1);
+  }
+  return record_type_diff_protobuf;
+}
+
+bool IRDiffToProtobufConverter::AddEnumUnderlyingTypeDiff(
+    abi_diff::UnderlyingTypeDiff *underlying_type_diff_protobuf,
+    const std::pair<std::string, std::string> *underlying_type_diff_ir) {
+  if (underlying_type_diff_protobuf == nullptr) {
+    return false;
+  }
+  underlying_type_diff_protobuf->set_old_type(underlying_type_diff_ir->first);
+  underlying_type_diff_protobuf->set_new_type(underlying_type_diff_ir->second);
+  return true;
+}
+
+static bool AddEnumFields(
+    google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> *dst,
+    const std::vector<const EnumFieldIR *> &enum_fields) {
+  for (auto &&enum_field : enum_fields) {
+    abi_dump::EnumFieldDecl *added_enum_field = dst->Add();
+    if (!SetIRToProtobufEnumField(added_enum_field, enum_field)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+static bool AddEnumFieldDiffs(
+    google::protobuf::RepeatedPtrField<abi_diff::EnumFieldDeclDiff> *dst,
+    const std::vector<EnumFieldDiffIR> &fields_diff_ir) {
+  for (auto &&field_diff_ir : fields_diff_ir) {
+    abi_diff::EnumFieldDeclDiff *field_diff_protobuf = dst->Add();
+    if (field_diff_protobuf == nullptr) {
+      return false;
+    }
+    if (!SetIRToProtobufEnumField(field_diff_protobuf->mutable_old_field(),
+                                  field_diff_ir.GetOldField()) ||
+        !SetIRToProtobufEnumField(field_diff_protobuf->mutable_new_field(),
+                                  field_diff_ir.GetNewField())) {
+      return false;
+    }
+  }
+  return true;
+}
+
+abi_diff::EnumTypeDiff IRDiffToProtobufConverter::ConvertEnumTypeDiffIR(
+    const EnumTypeDiffIR *enum_type_diff_ir) {
+  abi_diff::EnumTypeDiff enum_type_diff_protobuf;
+  enum_type_diff_protobuf.set_name(enum_type_diff_ir->GetName());
+  const std::pair<std::string, std::string> *underlying_type_diff =
+      enum_type_diff_ir->GetUnderlyingTypeDiff();
+  if ((underlying_type_diff != nullptr &&
+      !AddEnumUnderlyingTypeDiff(
+          enum_type_diff_protobuf.mutable_underlying_type_diff(),
+          underlying_type_diff)) ||
+      !AddEnumFields(enum_type_diff_protobuf.mutable_fields_removed(),
+                     enum_type_diff_ir->GetFieldsRemoved()) ||
+      !AddEnumFields(enum_type_diff_protobuf.mutable_fields_added(),
+                     enum_type_diff_ir->GetFieldsAdded()) ||
+      !AddEnumFieldDiffs(enum_type_diff_protobuf.mutable_fields_diff(),
+                         enum_type_diff_ir->GetFieldsDiff())) {
+    llvm::errs() << "Enum field diff could not be added\n";
+    ::exit(1);
+  }
+  return enum_type_diff_protobuf;
+}
+
+abi_diff::GlobalVarDeclDiff IRDiffToProtobufConverter::ConvertGlobalVarDiffIR(
+    const GlobalVarDiffIR *global_var_diff_ir) {
+  abi_diff::GlobalVarDeclDiff global_var_diff;
+  global_var_diff.set_name(global_var_diff_ir->GetName());
+  abi_dump::GlobalVarDecl *old_global_var = global_var_diff.mutable_old();
+  abi_dump::GlobalVarDecl *new_global_var = global_var_diff.mutable_new_();
+  if (old_global_var == nullptr || new_global_var == nullptr) {
+    llvm::errs() << "Globar Var diff could not be added\n";
+    ::exit(1);
+  }
+  *old_global_var =
+      IRToProtobufConverter::ConvertGlobalVarIR(
+          global_var_diff_ir->GetOldGlobalVar());
+  *new_global_var =
+      IRToProtobufConverter::ConvertGlobalVarIR(
+          global_var_diff_ir->GetNewGlobalVar());
+  return global_var_diff;
+}
+
+abi_diff::FunctionDeclDiff IRDiffToProtobufConverter::ConvertFunctionDiffIR(
+    const FunctionDiffIR *function_diff_ir) {
+  abi_diff::FunctionDeclDiff function_diff;
+  function_diff.set_name(function_diff_ir->GetName());
+  abi_dump::FunctionDecl *old_function = function_diff.mutable_old();
+  abi_dump::FunctionDecl *new_function = function_diff.mutable_new_();
+  if (old_function == nullptr || new_function == nullptr) {
+    llvm::errs() << "Function diff could not be added\n";
+    ::exit(1);
+  }
+  *old_function =
+      IRToProtobufConverter::ConvertFunctionIR(
+          function_diff_ir->GetOldFunction());
+  *new_function =
+      IRToProtobufConverter::ConvertFunctionIR(
+          function_diff_ir->GetNewFunction());
+  return function_diff;
+}
+
+bool ProtobufIRDumper::AddLinkableMessageIR (const LinkableMessageIR *lm) {
+  // No RTTI
+  switch (lm->GetKind()) {
+    case RecordTypeKind:
+      return AddRecordTypeIR(static_cast<const RecordTypeIR *>(lm));
+    case EnumTypeKind:
+      return AddEnumTypeIR(static_cast<const EnumTypeIR *>(lm));
+    case PointerTypeKind:
+      return AddPointerTypeIR(static_cast<const PointerTypeIR *>(lm));
+    case QualifiedTypeKind:
+      return AddQualifiedTypeIR(static_cast<const QualifiedTypeIR *>(lm));
+    case ArrayTypeKind:
+      return AddArrayTypeIR(static_cast<const ArrayTypeIR *>(lm));
+    case LvalueReferenceTypeKind:
+      return AddLvalueReferenceTypeIR(
+          static_cast<const LvalueReferenceTypeIR *>(lm));
+    case RvalueReferenceTypeKind:
+      return AddRvalueReferenceTypeIR(
+          static_cast<const RvalueReferenceTypeIR*>(lm));
+    case BuiltinTypeKind:
+      return AddBuiltinTypeIR(static_cast<const BuiltinTypeIR*>(lm));
+    case GlobalVarKind:
+      return AddGlobalVarIR(static_cast<const GlobalVarIR*>(lm));
+    case FunctionKind:
+      return AddFunctionIR(static_cast<const FunctionIR*>(lm));
+  }
+  return false;
+}
+
+bool ProtobufIRDumper::AddRecordTypeIR(const RecordTypeIR *recordp) {
+  abi_dump::RecordType *added_record_type = tu_ptr_->add_record_types();
+  if (!added_record_type) {
+    return false;
+  }
+  *added_record_type = ConvertRecordTypeIR(recordp);
+  return true;
+}
+
+bool ProtobufIRDumper::AddFunctionIR(const FunctionIR *functionp) {
+  abi_dump::FunctionDecl *added_function = tu_ptr_->add_functions();
+  if (!added_function) {
+    return false;
+  }
+  *added_function = ConvertFunctionIR(functionp);
+  return true;
+}
+
+bool ProtobufIRDumper::AddEnumTypeIR(const EnumTypeIR *enump) {
+  abi_dump::EnumType *added_enum_type = tu_ptr_->add_enum_types();
+  if (!added_enum_type) {
+    return false;
+  }
+  *added_enum_type = ConvertEnumTypeIR(enump);
+  return true;
+}
+
+bool ProtobufIRDumper::AddGlobalVarIR(const GlobalVarIR *global_varp) {
+  abi_dump::GlobalVarDecl *added_global_var = tu_ptr_->add_global_vars();
+  if (!added_global_var) {
+    return false;
+  }
+  *added_global_var = ConvertGlobalVarIR(global_varp);
+  return true;
+}
+
+bool ProtobufIRDumper::AddPointerTypeIR(const PointerTypeIR *pointerp) {
+  abi_dump::PointerType *added_pointer_type = tu_ptr_->add_pointer_types();
+  if (!added_pointer_type) {
+    return false;
+  }
+  *added_pointer_type = ConvertPointerTypeIR(pointerp);
+  return true;
+}
+
+bool ProtobufIRDumper::AddQualifiedTypeIR(const QualifiedTypeIR *qualtypep) {
+  abi_dump::QualifiedType *added_qualified_type =
+      tu_ptr_->add_qualified_types();
+  if (!added_qualified_type) {
+    return false;
+  }
+  *added_qualified_type = ConvertQualifiedTypeIR(qualtypep);
+  return true;
+}
+
+bool ProtobufIRDumper::AddBuiltinTypeIR(const BuiltinTypeIR *builtin_typep) {
+  abi_dump::BuiltinType *added_builtin_type =
+      tu_ptr_->add_builtin_types();
+  if (!added_builtin_type) {
+    return false;
+  }
+  *added_builtin_type = ConvertBuiltinTypeIR(builtin_typep);
+  return true;
+}
+
+bool ProtobufIRDumper::AddArrayTypeIR(const ArrayTypeIR *array_typep) {
+  abi_dump::ArrayType *added_array_type =
+      tu_ptr_->add_array_types();
+  if (!added_array_type) {
+    return false;
+  }
+  *added_array_type = ConvertArrayTypeIR(array_typep);
+  return true;
+}
+
+bool ProtobufIRDumper::AddLvalueReferenceTypeIR(
+    const LvalueReferenceTypeIR *lvalue_reference_typep) {
+  abi_dump::LvalueReferenceType *added_lvalue_reference_type =
+      tu_ptr_->add_lvalue_reference_types();
+  if (!added_lvalue_reference_type) {
+    return false;
+  }
+  *added_lvalue_reference_type =
+      ConvertLvalueReferenceTypeIR(lvalue_reference_typep);
+  return true;
+}
+
+bool ProtobufIRDumper::AddRvalueReferenceTypeIR(
+    const RvalueReferenceTypeIR *rvalue_reference_typep) {
+  abi_dump::RvalueReferenceType *added_rvalue_reference_type =
+      tu_ptr_->add_rvalue_reference_types();
+  if (!added_rvalue_reference_type) {
+    return false;
+  }
+  *added_rvalue_reference_type =
+      ConvertRvalueReferenceTypeIR(rvalue_reference_typep);
+  return true;
+}
+
+bool ProtobufIRDumper::Dump() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+  assert( tu_ptr_.get() != nullptr);
+  std::ofstream text_output(dump_path_);
+  google::protobuf::io::OstreamOutputStream text_os(&text_output);
+  return google::protobuf::TextFormat::Print(*tu_ptr_.get(), &text_os);
+}
+
+void ProtobufIRDiffDumper::AddLibNameIR(const std::string &name) {
+  diff_tu_->set_lib_name(name);
+}
+
+void ProtobufIRDiffDumper::AddArchIR(const std::string &arch) {
+  diff_tu_->set_arch(arch);
+}
+
+CompatibilityStatusIR ProtobufIRDiffDumper::GetCompatibilityStatusIR() {
+  if (diff_tu_->functions_removed().size() != 0 ||
+      diff_tu_->global_vars_removed().size() != 0 ||
+      diff_tu_->function_diffs().size() != 0 ||
+      diff_tu_->global_var_diffs().size() != 0 ||
+      diff_tu_->enum_type_diffs().size() != 0 ||
+      diff_tu_->record_type_diffs().size() != 0 ||
+      diff_tu_->removed_elf_functions().size() != 0 ||
+      diff_tu_->removed_elf_objects().size() != 0) {
+    return CompatibilityStatusIR::Incompatible;
+  }
+
+  CompatibilityStatusIR combined_status = CompatibilityStatusIR::Compatible;
+
+  if (diff_tu_->enum_type_extension_diffs().size() != 0 ||
+      diff_tu_->functions_added().size() != 0 ||
+      diff_tu_->global_vars_added().size() !=0 ||
+      diff_tu_->added_elf_functions().size() != 0 ||
+      diff_tu_->added_elf_objects().size() != 0) {
+    combined_status = combined_status | CompatibilityStatusIR::Extension;
+  }
+
+  if (diff_tu_->unreferenced_enum_type_diffs().size() != 0 ||
+      diff_tu_->unreferenced_enum_types_removed().size() != 0 ||
+      diff_tu_->unreferenced_record_types_removed().size() != 0 ||
+      diff_tu_->unreferenced_record_type_diffs().size() != 0 ||
+      diff_tu_->unreferenced_enum_type_extension_diffs().size() != 0 ||
+      diff_tu_->unreferenced_record_types_added().size() != 0 ||
+      diff_tu_->unreferenced_enum_types_added().size()) {
+    combined_status =
+        combined_status | CompatibilityStatusIR::UnreferencedChanges;
+  }
+
+  return combined_status;
+}
+
+void ProtobufIRDiffDumper::AddCompatibilityStatusIR(
+    CompatibilityStatusIR status) {
+  diff_tu_->set_compatibility_status(CompatibilityStatusIRToProtobuf(status));
+}
+
+bool ProtobufIRDiffDumper::AddDiffMessageIR(
+    const DiffMessageIR *message,
+    const std::string &type_stack,
+    DiffKind diff_kind) {
+  switch (message->Kind()) {
+    case RecordTypeKind:
+      return AddRecordTypeDiffIR(
+          static_cast<const RecordTypeDiffIR *>(message),
+          type_stack, diff_kind);
+    case EnumTypeKind:
+      return AddEnumTypeDiffIR(
+          static_cast<const EnumTypeDiffIR *>(message),
+          type_stack, diff_kind);
+    case GlobalVarKind:
+      return AddGlobalVarDiffIR(
+          static_cast<const GlobalVarDiffIR*>(message),
+          type_stack, diff_kind);
+    case FunctionKind:
+      return AddFunctionDiffIR(
+          static_cast<const FunctionDiffIR*>(message),
+          type_stack, diff_kind);
+    default:
+      break;
+  }
+  llvm::errs() << "Dump Diff attempted on something not a user defined type" <<
+                   "/ function / global variable\n";
+  return false;
+}
+
+bool ProtobufIRDiffDumper::AddLinkableMessageIR(
+    const LinkableMessageIR *message,
+    DiffKind diff_kind) {
+  switch (message->GetKind()) {
+    case RecordTypeKind:
+      return AddLoneRecordTypeDiffIR(
+          static_cast<const RecordTypeIR *>(message), diff_kind);
+    case EnumTypeKind:
+      return AddLoneEnumTypeDiffIR(
+          static_cast<const EnumTypeIR *>(message), diff_kind);
+    case GlobalVarKind:
+      return AddLoneGlobalVarDiffIR(
+          static_cast<const GlobalVarIR*>(message), diff_kind);
+    case FunctionKind:
+      return AddLoneFunctionDiffIR(
+          static_cast<const FunctionIR*>(message), diff_kind);
+    default:
+      break;
+  }
+  llvm::errs() << "Dump Diff attempted on something not a user defined type" <<
+                   "/ function / global variable\n";
+  return false;
+}
+
+bool ProtobufIRDiffDumper::AddElfSymbolMessageIR (const ElfSymbolIR *elf_symbol,
+                                                  DiffKind diff_kind) {
+  switch (elf_symbol->GetKind()) {
+    case ElfSymbolIR::ElfFunctionKind:
+      return AddElfFunctionIR(static_cast<const ElfFunctionIR *>(elf_symbol),
+                              diff_kind);
+      break;
+    case ElfSymbolIR::ElfObjectKind:
+      return AddElfObjectIR(static_cast<const ElfObjectIR *>(elf_symbol),
+                            diff_kind);
+      break;
+  }
+  // Any other kind is invalid
+  return false;
+}
+
+bool ProtobufIRDiffDumper::AddElfFunctionIR(
+    const ElfFunctionIR *elf_function_ir, DiffKind diff_kind) {
+  abi_dump::ElfFunction *added_elf_function = nullptr;
+  switch(diff_kind) {
+    case DiffKind::Removed:
+      added_elf_function = diff_tu_->add_removed_elf_functions();
+      break;
+    case DiffKind::Added:
+      added_elf_function = diff_tu_->add_added_elf_functions();
+      break;
+    default:
+      llvm::errs() << "Invalid call to AddElfFunctionIR\n";
+      return false;
+  }
+  if (added_elf_function == nullptr) {
+    return false;
+  }
+  *added_elf_function =
+      IRToProtobufConverter::ConvertElfFunctionIR(elf_function_ir);
+  return true;
+}
+
+bool ProtobufIRDiffDumper::AddElfObjectIR(
+    const ElfObjectIR *elf_object_ir, DiffKind diff_kind) {
+  abi_dump::ElfObject *added_elf_object = nullptr;
+  switch(diff_kind) {
+    case DiffKind::Removed:
+      added_elf_object = diff_tu_->add_removed_elf_objects();
+      break;
+    case DiffKind::Added:
+      added_elf_object = diff_tu_->add_added_elf_objects();
+      break;
+    default:
+      llvm::errs() << "Invalid call to AddElfObjectIR\n";
+      return false;
+  }
+  if (added_elf_object == nullptr) {
+    return false;
+  }
+  *added_elf_object =
+      IRToProtobufConverter::ConvertElfObjectIR(elf_object_ir);
+  return true;
+}
+
+bool ProtobufIRDiffDumper::AddLoneRecordTypeDiffIR(
+    const RecordTypeIR *record_type_ir,
+    DiffKind diff_kind) {
+  abi_dump::RecordType *added_record_type = nullptr;
+  switch (diff_kind) {
+    case DiffKind::Removed:
+      // Referenced record types do not get reported as added / removed,
+      // the diff shows up in the parent type / function/ global variable
+      // referencing the record.
+      added_record_type = diff_tu_->add_unreferenced_record_types_removed();
+      break;
+    case DiffKind::Added:
+      added_record_type = diff_tu_->add_unreferenced_record_types_added();
+      break;
+    default:
+      llvm::errs() << "Invalid call to AddLoneRecordTypeDiffIR\n";
+      return false;
+  }
+  if (added_record_type == nullptr) {
+    return false;
+  }
+  *added_record_type =
+      IRToProtobufConverter::ConvertRecordTypeIR(record_type_ir);
+  return true;
+}
+
+bool ProtobufIRDiffDumper::AddLoneFunctionDiffIR(
+    const FunctionIR *function_ir,
+    DiffKind diff_kind) {
+  abi_dump::FunctionDecl *added_function = nullptr;
+  switch (diff_kind) {
+    case DiffKind::Removed:
+      added_function = diff_tu_->add_functions_removed();
+      break;
+    case DiffKind::Added:
+      added_function = diff_tu_->add_functions_added();
+      break;
+    default:
+      llvm::errs() << "Invalid call to AddLoneFunctionDiffIR\n";
+      return false;
+  }
+  *added_function = IRToProtobufConverter::ConvertFunctionIR(function_ir);
+  return true;
+}
+
+bool ProtobufIRDiffDumper::AddLoneEnumTypeDiffIR(
+    const EnumTypeIR *enum_type_ir, DiffKind diff_kind) {
+  abi_dump::EnumType *added_enum_type = nullptr;
+  switch (diff_kind) {
+    case DiffKind::Removed:
+      // Referenced enum types do not get reported as added / removed,
+      // the diff shows up in the parent type / function/ global variable
+      // referencing the enum.
+      added_enum_type = diff_tu_->add_unreferenced_enum_types_removed();
+      break;
+    case DiffKind::Added:
+      added_enum_type = diff_tu_->add_unreferenced_enum_types_added();
+      break;
+    default:
+      llvm::errs() << "Invalid call to AddLoneRecordTypeDiffIR\n";
+      return false;
+  }
+  if (added_enum_type == nullptr) {
+    return false;
+  }
+  *added_enum_type = IRToProtobufConverter::ConvertEnumTypeIR(enum_type_ir);
+  return true;
+}
+
+bool ProtobufIRDiffDumper::AddLoneGlobalVarDiffIR(
+    const GlobalVarIR *global_var_ir, DiffKind diff_kind) {
+  abi_dump::GlobalVarDecl *added_global_var = nullptr;
+  switch (diff_kind) {
+    case DiffKind::Removed:
+      added_global_var = diff_tu_->add_global_vars_removed();
+      break;
+    case DiffKind::Added:
+      added_global_var = diff_tu_->add_global_vars_added();
+      break;
+    default:
+      llvm::errs() << "Invalid call to AddLoneFunctionDiffIR\n";
+      return false;
+  }
+  *added_global_var = IRToProtobufConverter::ConvertGlobalVarIR(global_var_ir);
+  return true;
+}
+
+bool ProtobufIRDiffDumper::AddRecordTypeDiffIR(
+    const RecordTypeDiffIR *record_diff_ir,
+    const std::string &type_stack,
+    DiffKind diff_kind) {
+  abi_diff::RecordTypeDiff *added_record_type_diff = nullptr;
+  switch (diff_kind) {
+    case DiffKind::Unreferenced:
+      added_record_type_diff = diff_tu_->add_unreferenced_record_type_diffs();
+      break;
+    case DiffKind::Referenced:
+      added_record_type_diff = diff_tu_->add_record_type_diffs();
+      break;
+    default:
+      break;
+  }
+  if (!added_record_type_diff) {
+    return false;
+  }
+
+  *added_record_type_diff =
+      IRDiffToProtobufConverter::ConvertRecordTypeDiffIR(record_diff_ir);
+  added_record_type_diff->set_type_stack(type_stack);
+  return true;
+}
+
+bool ProtobufIRDiffDumper::AddFunctionDiffIR(
+    const FunctionDiffIR *function_diff_ir, const std::string &type_stack,
+    DiffKind diff_kind) {
+  abi_diff::FunctionDeclDiff *added_function_diff =
+      diff_tu_->add_function_diffs();
+  if (!added_function_diff) {
+    return false;
+  }
+  *added_function_diff =
+      IRDiffToProtobufConverter::ConvertFunctionDiffIR(function_diff_ir);
+  return true;
+}
+
+bool ProtobufIRDiffDumper::AddEnumTypeDiffIR(const EnumTypeDiffIR *enum_diff_ir,
+                                             const std::string &type_stack,
+                                             DiffKind diff_kind) {
+  abi_diff::EnumTypeDiff *added_enum_type_diff = nullptr;
+  switch (diff_kind) {
+    case DiffKind::Unreferenced:
+      if (enum_diff_ir->IsExtended()) {
+        added_enum_type_diff =
+            diff_tu_->add_unreferenced_enum_type_extension_diffs();
+      } else {
+        added_enum_type_diff =
+            diff_tu_->add_unreferenced_enum_type_diffs();
+      }
+      break;
+    case DiffKind::Referenced:
+      if (enum_diff_ir->IsExtended()) {
+        added_enum_type_diff =
+            diff_tu_->add_enum_type_extension_diffs();
+      } else {
+        added_enum_type_diff =
+            diff_tu_->add_enum_type_diffs();
+      }
+      break;
+    default:
+      break;
+  }
+  if (!added_enum_type_diff) {
+    return false;
+  }
+  *added_enum_type_diff =
+      IRDiffToProtobufConverter::ConvertEnumTypeDiffIR(enum_diff_ir);
+  added_enum_type_diff->set_type_stack(type_stack);
+  return true;
+}
+
+bool ProtobufIRDiffDumper::AddGlobalVarDiffIR(
+    const GlobalVarDiffIR *global_var_diff_ir,
+    const std::string &type_stack,
+    DiffKind diff_kind) {
+  abi_diff::GlobalVarDeclDiff *added_global_var_diff =
+      diff_tu_->add_global_var_diffs();
+  if (!added_global_var_diff) {
+    return false;
+  }
+  *added_global_var_diff =
+      IRDiffToProtobufConverter::ConvertGlobalVarDiffIR(global_var_diff_ir);
+  return true;
+}
+
+bool ProtobufIRDiffDumper::Dump() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+  assert(diff_tu_.get() != nullptr);
+  std::ofstream text_output(dump_path_);
+  google::protobuf::io::OstreamOutputStream text_os(&text_output);
+  return google::protobuf::TextFormat::Print(*diff_tu_.get(), &text_os);
+}
+
+} //abi_util
diff --git a/vndk/tools/header-checker/proto/abi_diff.proto b/vndk/tools/header-checker/proto/abi_diff.proto
index 28dbd52..17cfc92 100644
--- a/vndk/tools/header-checker/proto/abi_diff.proto
+++ b/vndk/tools/header-checker/proto/abi_diff.proto
@@ -4,97 +4,112 @@
 
 package abi_diff;
 
-message RecordFieldDeclDiff {
-  optional abi_dump.RecordFieldDecl old = 1;
-  optional abi_dump.RecordFieldDecl new = 2;
-  optional uint32 index = 3;
+message TypeInfo {
+  optional uint64 size = 1;
+  optional uint32 alignment = 2;
 }
 
-message EnumFieldDeclDiff {
-  optional abi_dump.EnumFieldDecl old = 1;
-  optional abi_dump.EnumFieldDecl new = 2;
-  optional uint32 index = 3;
+message TypeInfoDiff {
+  optional TypeInfo old_type_info  = 1;
+  optional TypeInfo new_type_info  = 2;
+}
+
+message VTableLayoutDiff {
+  optional abi_dump.VTableLayout old_vtable = 1;
+  optional abi_dump.VTableLayout new_vtable = 2;
+}
+
+message RecordFieldDeclDiff {
+  optional abi_dump.RecordFieldDecl old_field = 1;
+  optional abi_dump.RecordFieldDecl new_field = 2;
 }
 
 message CXXBaseSpecifierDiff {
-  optional abi_dump.CXXBaseSpecifier old = 1;
-  optional abi_dump.CXXBaseSpecifier new = 2;
-  optional uint32 index = 3;
+  repeated abi_dump.CXXBaseSpecifier old_bases = 1;
+  repeated abi_dump.CXXBaseSpecifier new_bases = 2;
 }
 
-message CXXVTableDiff {
-  optional abi_dump.VTableComponent old = 1;
-  optional abi_dump.VTableComponent new = 2;
-  optional uint32 index = 3;
+message RecordTypeDiff {
+  optional string name = 1;
+  optional string type_stack = 2;
+  optional TypeInfoDiff type_info_diff = 3;
+  repeated abi_dump.RecordFieldDecl fields_removed = 4;
+  repeated RecordFieldDeclDiff fields_diff = 5;
+  optional CXXBaseSpecifierDiff bases_diff = 6;
+  optional VTableLayoutDiff vtable_layout_diff = 7;
 }
 
-message BasicNamedAndTypedDeclDiff {
-  optional abi_dump.BasicNamedAndTypedDecl old = 1;
-  optional abi_dump.BasicNamedAndTypedDecl new = 2;
+message UnderlyingTypeDiff {
+  optional string old_type  = 1;
+  optional string new_type  = 2;
 }
 
-message RecordDeclDiff {
-  repeated RecordFieldDeclDiff field_diffs = 1;
-  repeated CXXBaseSpecifierDiff base_diffs = 2;
-  repeated CXXVTableDiff vtable_diffs = 3;
-  optional BasicNamedAndTypedDeclDiff type_diff = 4;
-  optional string name = 5;
+message EnumFieldDeclDiff {
+  optional abi_dump.EnumFieldDecl old_field = 1;
+  optional abi_dump.EnumFieldDecl new_field = 2;
 }
 
-message EnumDeclDiff {
-  repeated EnumFieldDeclDiff field_diffs = 1;
-  optional BasicNamedAndTypedDeclDiff type_diff = 2;
-  optional string name = 3;
-}
-
-message ReturnTypeDiff {
-  optional abi_dump.BasicNamedAndTypedDecl old = 1;
-  optional abi_dump.BasicNamedAndTypedDecl new = 2;
-}
-
-message ParamDeclDiff {
-  optional abi_dump.ParamDecl old = 1;
-  optional abi_dump.ParamDecl new = 2;
-  optional uint32 index = 3;
+message EnumTypeDiff {
+  optional string type_stack = 1;
+  optional string name = 2;
+  repeated EnumFieldDeclDiff fields_diff = 3;
+  optional UnderlyingTypeDiff underlying_type_diff = 4;
+  repeated abi_dump.EnumFieldDecl fields_added = 5;
+  repeated abi_dump.EnumFieldDecl fields_removed = 6;
 }
 
 message FunctionDeclDiff {
-  optional ReturnTypeDiff return_type_diffs = 1;
-  repeated ParamDeclDiff param_diffs = 2;
-  optional string name = 3;
+  // Template diffs are not required since in C++, they will show up in mangled
+  // names and in C, templates are not supported.
+  optional string type_stack = 1;
+  optional string name = 2;
+  optional abi_dump.FunctionDecl old = 3;
+  optional abi_dump.FunctionDecl new = 4;
 }
 
 message GlobalVarDeclDiff {
-  optional BasicNamedAndTypedDeclDiff type_diff = 1;
-}
-
-enum CompatibilityStatus {
-  COMPATIBLE = 0;
-  EXTENSION = 1;
-  INCOMPATIBLE = 4;
+  optional string type_stack = 1;
+  optional string name = 2;
+  optional abi_dump.GlobalVarDecl old = 3; // Old global var
+  optional abi_dump.GlobalVarDecl new = 4; // New global var
 }
 
 message TranslationUnitDiff {
   // Library Name
   optional string lib_name = 1;
   optional string arch = 2;
-  // Differing Elements.
-  repeated RecordDeclDiff records_diff = 3;
-  repeated EnumDeclDiff enums_diff = 4;
-  repeated FunctionDeclDiff functions_diff = 5;
-  repeated GlobalVarDeclDiff global_vars_diff = 6;
-  // Removed Elements.
-  repeated abi_dump.RecordDecl records_removed = 7;
-  repeated abi_dump.FunctionDecl functions_removed = 8;
-  repeated abi_dump.EnumDecl enums_removed = 9;
-  repeated abi_dump.GlobalVarDecl global_vars_removed = 10;
-  // Added Elements.
-  repeated abi_dump.RecordDecl records_added = 11;
-  repeated abi_dump.FunctionDecl functions_added = 12;
-  repeated abi_dump.EnumDecl enums_added = 13;
-  repeated abi_dump.GlobalVarDecl global_vars_added = 14;
+  // Records.
+  repeated RecordTypeDiff record_type_diffs = 3;
+  repeated RecordTypeDiff unreferenced_record_type_diffs = 4;
+  repeated abi_dump.RecordType unreferenced_record_types_removed = 5;
+  repeated abi_dump.RecordType unreferenced_record_types_added = 6;
+
+  // Enums
+  repeated EnumTypeDiff enum_type_diffs = 7;
+  repeated EnumTypeDiff enum_type_extension_diffs = 8;
+  repeated EnumTypeDiff unreferenced_enum_type_diffs = 9;
+  repeated EnumTypeDiff unreferenced_enum_type_extension_diffs = 10;
+  repeated abi_dump.EnumType unreferenced_enum_types_removed = 11;
+  repeated abi_dump.EnumType unreferenced_enum_types_added = 12;
+
+  // Functions and Global variables.
+  repeated FunctionDeclDiff function_diffs = 13;
+  repeated GlobalVarDeclDiff global_var_diffs = 14;
+
+  repeated abi_dump.FunctionDecl functions_removed = 15;
+  repeated abi_dump.GlobalVarDecl global_vars_removed = 16;
+
+  repeated abi_dump.FunctionDecl functions_added = 17;
+  repeated abi_dump.GlobalVarDecl global_vars_added = 18;
+
+  repeated abi_dump.ElfFunction added_elf_functions = 19;
+  repeated abi_dump.ElfFunction removed_elf_functions = 20;
+
+  repeated abi_dump.ElfObject added_elf_objects = 21;
+  repeated abi_dump.ElfObject removed_elf_objects = 22;
+
   // Compatiblity Status
-  optional CompatibilityStatus compatibility_status = 15;
+  optional CompatibilityStatus compatibility_status = 23;
 }
 
 // Not merged with TranslationUnitDiff to allow future extensions.
@@ -108,3 +123,9 @@
 message MergedTranslationUnitDiff {
   repeated ConciseDiffReportInformation diff_reports = 1;
 }
+
+enum CompatibilityStatus {
+  COMPATIBLE = 0;
+  EXTENSION = 1;
+  INCOMPATIBLE = 4;
+}
diff --git a/vndk/tools/header-checker/proto/abi_dump.proto b/vndk/tools/header-checker/proto/abi_dump.proto
index 3633d20..870329c 100644
--- a/vndk/tools/header-checker/proto/abi_dump.proto
+++ b/vndk/tools/header-checker/proto/abi_dump.proto
@@ -2,50 +2,84 @@
 
 package abi_dump;
 
-message BasicTypeAbi {
-  // The type's name. for eg : a record field's type.
-  optional string name = 1;
-  // Optional since templated types will not have this information.
-  optional uint64 size = 2 [default = 0];
-  optional uint32 alignment = 3 [default = 0];
-}
-
 enum AccessSpecifier {
   public_access = 1;
   private_access = 2;
   protected_access = 3;
 }
 
+enum RecordKind {
+  struct_kind = 1;
+  class_kind = 2;
+  union_kind = 3;
+}
+
 message BasicNamedAndTypedDecl {
-  optional BasicTypeAbi type_abi = 1;
   // The TypedDecl's name.
-  optional string name = 2;
-  optional AccessSpecifier access = 3;
-  optional string linker_set_key = 4;
+  optional string name = 1;
+  optional uint64 size = 2 [default = 0];
+  optional uint32 alignment = 3 [default = 0];
+  optional string referenced_type = 4;
+  optional string source_file = 5;
+  optional string linker_set_key = 6;
+}
+
+message ArrayType {
+  optional BasicNamedAndTypedDecl type_info = 1;
+}
+
+message PointerType {
+  optional BasicNamedAndTypedDecl type_info = 1;
+}
+
+message QualifiedType {
+  optional BasicNamedAndTypedDecl type_info = 1;
+  optional bool is_const = 6;
+  optional bool is_volatile = 7;
+  optional bool is_restricted = 8;
+}
+
+message BuiltinType {
+  optional BasicNamedAndTypedDecl type_info = 1;
+  optional bool is_unsigned = 2;
+  optional bool is_integral = 3;
+}
+
+message LvalueReferenceType {
+  optional BasicNamedAndTypedDecl type_info = 1;
+}
+
+message RvalueReferenceType {
+  optional BasicNamedAndTypedDecl type_info = 1;
 }
 
 message FunctionDecl {
-  optional BasicNamedAndTypedDecl basic_abi = 1;
-  // Mangled name.
-  optional string mangled_function_name = 2;
+  // Return type reference
+  optional string return_type = 1;
+  optional string function_name = 2;
   optional string source_file = 3;
   repeated ParamDecl parameters = 4;
   optional TemplateInfo template_info = 5;
+  optional string linker_set_key = 6;
+  optional AccessSpecifier access = 7 [default = public_access];
 }
 
 message ParamDecl {
-  optional BasicNamedAndTypedDecl basic_abi = 1;
+  optional string referenced_type = 1;
   optional bool default_arg = 2;
 }
 
 message RecordFieldDecl {
   // For future additions.
-  optional BasicNamedAndTypedDecl basic_abi = 1;
+  optional string referenced_type = 1;
+  optional uint64 field_offset = 2;
+  optional string field_name = 3;
+  optional AccessSpecifier access = 4 [default = public_access];
 }
 
 message EnumFieldDecl {
-  optional BasicNamedAndTypedDecl basic_abi = 1;
-  optional int64 enum_field_value = 2; // assumption: fits int64
+  optional int64 enum_field_value = 1; // assumption: fits int64
+  optional string name = 3;
 }
 
 message TemplateInfo {
@@ -53,17 +87,13 @@
 }
 
 message TemplateElement {
-  optional BasicTemplateElementAbi basic_abi = 1;
-  message BasicTemplateElementAbi {
-    optional BasicTypeAbi type_abi = 1;
-    optional string name = 2;
-    optional string linker_set_key = 3;
-  }
+  optional string referenced_type = 1;
 }
 
 message CXXBaseSpecifier {
-  optional BasicNamedAndTypedDecl basic_abi = 1;
+  optional string referenced_type = 1;
   optional bool is_virtual = 2;
+  optional AccessSpecifier access = 3;
 }
 
 message VTableComponent {
@@ -89,30 +119,51 @@
   repeated VTableComponent vtable_components = 1;
 }
 
-message RecordDecl {
-  optional BasicNamedAndTypedDecl basic_abi = 1;
+message RecordType {
+  optional BasicNamedAndTypedDecl type_info = 1;
   repeated RecordFieldDecl fields = 2;
   repeated CXXBaseSpecifier base_specifiers = 3;
-  optional string source_file = 4;
   optional TemplateInfo template_info = 5;
-  optional string mangled_record_name = 6;
   optional VTableLayout vtable_layout = 7;
+  optional AccessSpecifier access = 8 [default = public_access];
+  optional bool is_anonymous = 9;
+  optional RecordKind record_kind = 10 [default = struct_kind];
 }
 
-message EnumDecl {
-  optional BasicNamedAndTypedDecl basic_abi = 1;
-  repeated EnumFieldDecl enum_fields = 2;
-  optional string source_file = 3;
+message EnumType {
+  optional BasicNamedAndTypedDecl type_info = 1;
+  optional string underlying_type = 2;
+  repeated EnumFieldDecl enum_fields = 3;
+  optional AccessSpecifier access = 4 [default = public_access];
 }
 
 message GlobalVarDecl {
-  optional BasicNamedAndTypedDecl basic_abi = 1;
+  optional string name = 1;
   optional string source_file = 2;
+  optional string linker_set_key = 3;
+  optional string referenced_type = 4;
+  optional AccessSpecifier access = 5 [default = public_access];
+}
+
+message ElfFunction {
+  optional string name = 1;
+}
+
+message ElfObject {
+  optional string name = 1;
 }
 
 message TranslationUnit {
-  repeated RecordDecl records = 1;
-  repeated FunctionDecl functions = 2;
-  repeated EnumDecl enums = 3;
-  repeated GlobalVarDecl global_vars = 4;
+  repeated RecordType record_types = 1;
+  repeated EnumType enum_types = 2;
+  repeated PointerType pointer_types = 3;
+  repeated LvalueReferenceType lvalue_reference_types = 4;
+  repeated RvalueReferenceType rvalue_reference_types = 5;
+  repeated BuiltinType builtin_types = 6;
+  repeated QualifiedType qualified_types = 7;
+  repeated ArrayType array_types = 8;
+  repeated FunctionDecl functions = 9;
+  repeated GlobalVarDecl global_vars = 10;
+  repeated ElfFunction elf_functions = 11;
+  repeated ElfObject elf_objects = 12;
 }
diff --git a/vndk/tools/header-checker/tests/input/example1.h b/vndk/tools/header-checker/tests/input/example1.h
index c00cf06..1ff0c1c 100644
--- a/vndk/tools/header-checker/tests/input/example1.h
+++ b/vndk/tools/header-checker/tests/input/example1.h
@@ -7,9 +7,21 @@
 extern "C" {
 #endif
 
+struct ForwardDeclaration;
+int uses_forward_decl(struct ForwardDeclaration *);
+
 struct Hello {
   int foo;
   int bar;
+  enum {A, B} enum_field;
+  enum {C, D} enum_field2;
+  struct {
+    int a;
+    int b;
+    struct {
+      int c;
+    };
+  };
 };
 
 #if defined(__cplusplus)
@@ -24,8 +36,17 @@
   cfloat_type cpp_bar;
   virtual int again() { return 0; }
   CPPHello() : cpp_foo(20), cpp_bar(1.234) { }
+  enum Bla{BLA = 1};
+  int test_enum() {return CPPHello::BLA;}
 };
 
+
+void fooVariadic (int &, int *, ...);
+
+int boo (const CPPHello, int *, float *) {
+  return CPPHello::BLA;
+}
+
 template<typename T>
 struct StackNode {
 public:
@@ -63,7 +84,7 @@
 template<typename T>
 class List
 {
-protected:
+public:
     /*
      * One element in the list.
      */
@@ -74,6 +95,7 @@
         inline T& getRef() { return mVal; }
         inline const T& getRef() const { return mVal; }
     private:
+        void PrivateNode();
         friend class List;
         friend class _ListIterator;
         T           mVal;
@@ -83,11 +105,20 @@
     _Node *middle;
 };
 
+
 typedef List<float> float_list;
 float_list float_list_test;
 
-
 typedef List<int> int_list;
 int_list int_list_test;
+List<float>::_Node node(2);
+int ListMangle(int_list *, StackNode<int> *);
+
+template<typename IChild, typename IParent, typename BpChild, typename BpParent>
+List<IChild> castInterface(List<IParent> parent, const char *childIndicator, bool emitError) {return List<IChild>();}
+
+void format() {
+castInterface<float, float, float , float>(List<float>(), "foo", true);
+}
 
 #endif  // EXAMPLE1_H_
diff --git a/vndk/tools/header-checker/tests/input/example2.h b/vndk/tools/header-checker/tests/input/example2.h
index acf0f42..bc225eb 100644
--- a/vndk/tools/header-checker/tests/input/example2.h
+++ b/vndk/tools/header-checker/tests/input/example2.h
@@ -22,6 +22,7 @@
   int bar_again;
   static int hello_forever;
   virtual int again();
+  virtual ~HelloAgain() {}
 };
 struct NowWeCrash;
 } // namespace test2
diff --git a/vndk/tools/vndk-compliance/parse-and-fix-errors.sh b/vndk/tools/vndk-compliance/parse-and-fix-errors.sh
index 84c6bbd..b4f6216 100755
--- a/vndk/tools/vndk-compliance/parse-and-fix-errors.sh
+++ b/vndk/tools/vndk-compliance/parse-and-fix-errors.sh
@@ -30,10 +30,10 @@
 cat log | grep "FAILED\|error:" > log.error
 
 #libs that should be added to LOCAL_HEADER_LIBRARIES
-ADD_TO_HEADER_LIBS=(hardware system)
+ADD_TO_HEADER_LIBS=(hardware system cutils utils)
 
 #libs that should be added to LOCAL_SHARED_LIBRARIES
-ADD_TO_SHARED_LIBS=(cutils utils log)
+ADD_TO_SHARED_LIBS=(log)
 
 ALL_LIBS=(${ADD_TO_HEADER_LIBS[@]} ${ADD_TO_SHARED_LIBS[@]})