Home | History | Annotate | Download | only in src
      1 // Copyright (C) 2017 The Android Open Source Project
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include <ir_representation_protobuf.h>
     16 
     17 #include <llvm/Support/raw_ostream.h>
     18 
     19 #include <fstream>
     20 #include <iostream>
     21 #include <string>
     22 #include <memory>
     23 
     24 namespace abi_util {
     25 
     26 static bool IsPresentInExportedHeaders(
     27     const LinkableMessageIR &linkable_message,
     28     const std::set<std::string> *exported_headers) {
     29   if (exported_headers == nullptr || exported_headers->empty()) {
     30     return true;
     31   }
     32   return exported_headers->find(linkable_message.GetSourceFile())
     33       != exported_headers->end();
     34 }
     35 
     36 void ProtobufTextFormatToIRReader::ReadTypeInfo(
     37     const abi_dump::BasicNamedAndTypedDecl &type_info,
     38     TypeIR *typep) {
     39   typep->SetLinkerSetKey(type_info.linker_set_key());
     40   typep->SetName(type_info.name());
     41   typep->SetSourceFile(type_info.source_file());
     42   typep->SetReferencedType(type_info.referenced_type());
     43   typep->SetSelfType(type_info.self_type());
     44   typep->SetSize(type_info.size());
     45   typep->SetAlignment(type_info.alignment());
     46 }
     47 
     48 bool ProtobufTextFormatToIRReader::ReadDump(const std::string &dump_file) {
     49   abi_dump::TranslationUnit tu;
     50   std::ifstream input(dump_file);
     51   google::protobuf::io::IstreamInputStream text_is(&input);
     52 
     53   if (!google::protobuf::TextFormat::Parse(&text_is, &tu)) {
     54     llvm::errs() << "Failed to parse protobuf TextFormat file\n";
     55     return false;
     56   }
     57   ReadFunctions(tu);
     58   ReadGlobalVariables(tu);
     59 
     60   ReadEnumTypes(tu);
     61   ReadRecordTypes(tu);
     62   ReadFunctionTypes(tu);
     63   ReadArrayTypes(tu);
     64   ReadPointerTypes(tu);
     65   ReadQualifiedTypes(tu);
     66   ReadBuiltinTypes(tu);
     67   ReadLvalueReferenceTypes(tu);
     68   ReadRvalueReferenceTypes(tu);
     69 
     70   ReadElfFunctions(tu);
     71   ReadElfObjects(tu);
     72   return true;
     73 }
     74 
     75 TemplateInfoIR ProtobufTextFormatToIRReader::TemplateInfoProtobufToIR(
     76     const abi_dump::TemplateInfo &template_info_protobuf) {
     77   TemplateInfoIR template_info_ir;
     78   for (auto &&template_element : template_info_protobuf.elements()) {
     79     TemplateElementIR template_element_ir(template_element.referenced_type());
     80     template_info_ir.AddTemplateElement(std::move(template_element_ir));
     81   }
     82   return template_info_ir;
     83 }
     84 
     85 template< typename T>
     86 static void SetupCFunctionLikeIR(const T &cfunction_like_protobuf,
     87                                  CFunctionLikeIR *cfunction_like_ir) {
     88   cfunction_like_ir->SetReturnType(cfunction_like_protobuf.return_type());
     89   for (auto &&parameter: cfunction_like_protobuf.parameters()) {
     90     ParamIR param_ir(parameter.referenced_type(), parameter.default_arg(),
     91                      false);
     92     cfunction_like_ir->AddParameter(std::move(param_ir));
     93   }
     94 }
     95 
     96 FunctionIR ProtobufTextFormatToIRReader::FunctionProtobufToIR(
     97     const abi_dump::FunctionDecl &function_protobuf) {
     98   FunctionIR function_ir;
     99   function_ir.SetReturnType(function_protobuf.return_type());
    100   function_ir.SetLinkerSetKey(function_protobuf.linker_set_key());
    101   function_ir.SetName(function_protobuf.function_name());
    102   function_ir.SetAccess(AccessProtobufToIR(function_protobuf.access()));
    103   function_ir.SetSourceFile(function_protobuf.source_file());
    104   // Set parameters
    105   for (auto &&parameter: function_protobuf.parameters()) {
    106     ParamIR param_ir(parameter.referenced_type(), parameter.default_arg(),
    107                      parameter.is_this_ptr());
    108     function_ir.AddParameter(std::move(param_ir));
    109   }
    110   // Set Template info
    111   function_ir.SetTemplateInfo(
    112       TemplateInfoProtobufToIR(function_protobuf.template_info()));
    113   return function_ir;
    114 }
    115 
    116 FunctionTypeIR ProtobufTextFormatToIRReader::FunctionTypeProtobufToIR(
    117     const abi_dump::FunctionType &function_type_protobuf) {
    118   FunctionTypeIR function_type_ir;
    119   ReadTypeInfo(function_type_protobuf.type_info(), &function_type_ir);
    120   SetupCFunctionLikeIR(function_type_protobuf, &function_type_ir);
    121   return function_type_ir;
    122 }
    123 
    124 VTableLayoutIR ProtobufTextFormatToIRReader::VTableLayoutProtobufToIR(
    125     const abi_dump::VTableLayout &vtable_layout_protobuf) {
    126   VTableLayoutIR vtable_layout_ir;
    127   for (auto &&vtable_component : vtable_layout_protobuf.vtable_components()) {
    128     VTableComponentIR vtable_component_ir(
    129         vtable_component.mangled_component_name(),
    130         VTableComponentKindProtobufToIR(vtable_component.kind()),
    131         vtable_component.component_value());
    132     vtable_layout_ir.AddVTableComponent(std::move(vtable_component_ir));
    133   }
    134   return vtable_layout_ir;
    135 }
    136 
    137 std::vector<RecordFieldIR>
    138 ProtobufTextFormatToIRReader::RecordFieldsProtobufToIR(
    139     const google::protobuf::RepeatedPtrField<abi_dump::RecordFieldDecl> &rfp) {
    140   std::vector<RecordFieldIR> record_type_fields_ir;
    141   for (auto &&field : rfp) {
    142     RecordFieldIR record_field_ir(field.field_name(), field.referenced_type(),
    143                                   field.field_offset(),
    144                                   AccessProtobufToIR(field.access()));
    145     record_type_fields_ir.emplace_back(std::move(record_field_ir));
    146   }
    147   return record_type_fields_ir;
    148 }
    149 
    150 std::vector<CXXBaseSpecifierIR>
    151 ProtobufTextFormatToIRReader::RecordCXXBaseSpecifiersProtobufToIR(
    152     const google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> &rbs) {
    153   std::vector<CXXBaseSpecifierIR> record_type_bases_ir;
    154   for (auto &&base : rbs) {
    155     CXXBaseSpecifierIR record_base_ir(
    156         base.referenced_type(), base.is_virtual(),
    157         AccessProtobufToIR(base.access()));
    158     record_type_bases_ir.emplace_back(std::move(record_base_ir));
    159   }
    160   return record_type_bases_ir;
    161 }
    162 
    163 RecordTypeIR ProtobufTextFormatToIRReader::RecordTypeProtobufToIR(
    164     const abi_dump::RecordType &record_type_protobuf) {
    165   RecordTypeIR record_type_ir;
    166   ReadTypeInfo(record_type_protobuf.type_info(), &record_type_ir);
    167   record_type_ir.SetTemplateInfo(
    168       TemplateInfoProtobufToIR(record_type_protobuf.template_info()));
    169   record_type_ir.SetAccess(AccessProtobufToIR(record_type_protobuf.access()));
    170   record_type_ir.SetVTableLayout(
    171       VTableLayoutProtobufToIR(record_type_protobuf.vtable_layout()));
    172   // Get fields
    173   record_type_ir.SetRecordFields(RecordFieldsProtobufToIR(
    174       record_type_protobuf.fields()));
    175   // Base Specifiers
    176   record_type_ir.SetCXXBaseSpecifiers(RecordCXXBaseSpecifiersProtobufToIR(
    177       record_type_protobuf.base_specifiers()));
    178   record_type_ir.SetRecordKind(
    179       RecordKindProtobufToIR(record_type_protobuf.record_kind()));
    180   record_type_ir.SetAnonymity(record_type_protobuf.is_anonymous());
    181   record_type_ir.SetUniqueId(record_type_protobuf.tag_info().unique_id());
    182   return record_type_ir;
    183 }
    184 
    185 std::vector<EnumFieldIR>
    186 ProtobufTextFormatToIRReader::EnumFieldsProtobufToIR(
    187     const google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> &efp) {
    188   std::vector<EnumFieldIR> enum_type_fields_ir;
    189   for (auto &&field : efp) {
    190     EnumFieldIR enum_field_ir(field.name(), field.enum_field_value());
    191     enum_type_fields_ir.emplace_back(std::move(enum_field_ir));
    192   }
    193   return enum_type_fields_ir;
    194 }
    195 
    196 EnumTypeIR ProtobufTextFormatToIRReader::EnumTypeProtobufToIR(
    197     const abi_dump::EnumType &enum_type_protobuf) {
    198   EnumTypeIR enum_type_ir;
    199   ReadTypeInfo(enum_type_protobuf.type_info(), &enum_type_ir);
    200   enum_type_ir.SetUnderlyingType(enum_type_protobuf.underlying_type());
    201   enum_type_ir.SetAccess(AccessProtobufToIR(enum_type_protobuf.access()));
    202   enum_type_ir.SetFields(
    203       EnumFieldsProtobufToIR(enum_type_protobuf.enum_fields()));
    204   enum_type_ir.SetUniqueId(enum_type_protobuf.tag_info().unique_id());
    205   return enum_type_ir;
    206 }
    207 
    208 void ProtobufTextFormatToIRReader::ReadGlobalVariables(
    209     const abi_dump::TranslationUnit &tu) {
    210   for (auto &&global_variable_protobuf : tu.global_vars()) {
    211     GlobalVarIR global_variable_ir;
    212     global_variable_ir.SetName(global_variable_protobuf.name());
    213     global_variable_ir.SetAccess(AccessProtobufToIR(global_variable_protobuf.access()));
    214     global_variable_ir.SetSourceFile(global_variable_protobuf.source_file());
    215     global_variable_ir.SetReferencedType(
    216         global_variable_protobuf.referenced_type());
    217     global_variable_ir.SetLinkerSetKey(
    218         global_variable_protobuf.linker_set_key());
    219     if (!IsPresentInExportedHeaders(global_variable_ir, exported_headers_)) {
    220       continue;
    221     }
    222     global_variables_.insert(
    223         {global_variable_ir.GetLinkerSetKey(), std::move(global_variable_ir)});
    224   }
    225 }
    226 
    227 void ProtobufTextFormatToIRReader::ReadPointerTypes(
    228     const abi_dump::TranslationUnit &tu) {
    229   for (auto &&pointer_type_protobuf : tu.pointer_types()) {
    230     PointerTypeIR pointer_type_ir;
    231     ReadTypeInfo(pointer_type_protobuf.type_info(), &pointer_type_ir);
    232     if (!IsPresentInExportedHeaders(pointer_type_ir, exported_headers_)) {
    233       continue;
    234     }
    235     AddToMapAndTypeGraph(std::move(pointer_type_ir), &pointer_types_,
    236                          &type_graph_);
    237   }
    238 }
    239 
    240 void ProtobufTextFormatToIRReader::ReadBuiltinTypes(
    241     const abi_dump::TranslationUnit &tu) {
    242   for (auto &&builtin_type_protobuf : tu.builtin_types()) {
    243     BuiltinTypeIR builtin_type_ir;
    244     ReadTypeInfo(builtin_type_protobuf.type_info(), &builtin_type_ir);
    245     builtin_type_ir.SetSignedness(builtin_type_protobuf.is_unsigned());
    246     builtin_type_ir.SetIntegralType(builtin_type_protobuf.is_integral());
    247     AddToMapAndTypeGraph(std::move(builtin_type_ir), &builtin_types_,
    248                          &type_graph_);
    249   }
    250 }
    251 
    252 void ProtobufTextFormatToIRReader::ReadQualifiedTypes(
    253     const abi_dump::TranslationUnit &tu) {
    254   for (auto &&qualified_type_protobuf : tu.qualified_types()) {
    255     QualifiedTypeIR qualified_type_ir;
    256     ReadTypeInfo(qualified_type_protobuf.type_info(), &qualified_type_ir);
    257     qualified_type_ir.SetConstness(qualified_type_protobuf.is_const());
    258     qualified_type_ir.SetVolatility(qualified_type_protobuf.is_volatile());
    259     qualified_type_ir.SetRestrictedness(
    260         qualified_type_protobuf.is_restricted());
    261     if (!IsPresentInExportedHeaders(qualified_type_ir, exported_headers_)) {
    262       continue;
    263     }
    264     AddToMapAndTypeGraph(std::move(qualified_type_ir), &qualified_types_,
    265                          &type_graph_);
    266   }
    267 }
    268 
    269 void ProtobufTextFormatToIRReader::ReadArrayTypes(
    270     const abi_dump::TranslationUnit &tu) {
    271   for (auto &&array_type_protobuf : tu.array_types()) {
    272     ArrayTypeIR array_type_ir;
    273     ReadTypeInfo(array_type_protobuf.type_info(), &array_type_ir);
    274     if (!IsPresentInExportedHeaders(array_type_ir, exported_headers_)) {
    275       continue;
    276     }
    277     AddToMapAndTypeGraph(std::move(array_type_ir), &array_types_,
    278                          &type_graph_);
    279   }
    280 }
    281 
    282 void ProtobufTextFormatToIRReader::ReadLvalueReferenceTypes(
    283     const abi_dump::TranslationUnit &tu) {
    284   for (auto &&lvalue_reference_type_protobuf : tu.lvalue_reference_types()) {
    285     LvalueReferenceTypeIR lvalue_reference_type_ir;
    286     ReadTypeInfo(lvalue_reference_type_protobuf.type_info(),
    287                  &lvalue_reference_type_ir);
    288     if (!IsPresentInExportedHeaders(lvalue_reference_type_ir,
    289                                     exported_headers_)) {
    290       continue;
    291     }
    292     AddToMapAndTypeGraph(std::move(lvalue_reference_type_ir),
    293                          &lvalue_reference_types_, &type_graph_);
    294   }
    295 }
    296 
    297 void ProtobufTextFormatToIRReader::ReadRvalueReferenceTypes(
    298     const abi_dump::TranslationUnit &tu) {
    299   for (auto &&rvalue_reference_type_protobuf : tu.rvalue_reference_types()) {
    300     RvalueReferenceTypeIR rvalue_reference_type_ir;
    301     ReadTypeInfo(rvalue_reference_type_protobuf.type_info(),
    302                  &rvalue_reference_type_ir);
    303     if (!IsPresentInExportedHeaders(rvalue_reference_type_ir,
    304                                     exported_headers_)) {
    305       continue;
    306     }
    307     AddToMapAndTypeGraph(std::move(rvalue_reference_type_ir),
    308                          &rvalue_reference_types_, &type_graph_);
    309   }
    310 }
    311 
    312 void ProtobufTextFormatToIRReader::ReadFunctions(
    313     const abi_dump::TranslationUnit &tu) {
    314   for (auto &&function_protobuf : tu.functions()) {
    315     FunctionIR function_ir = FunctionProtobufToIR(function_protobuf);
    316     if (!IsPresentInExportedHeaders(function_ir, exported_headers_)) {
    317       continue;
    318     }
    319     functions_.insert({function_ir.GetLinkerSetKey(), std::move(function_ir)});
    320   }
    321 }
    322 
    323 void ProtobufTextFormatToIRReader::ReadRecordTypes(
    324     const abi_dump::TranslationUnit &tu) {
    325   for (auto &&record_type_protobuf : tu.record_types()) {
    326     RecordTypeIR record_type_ir = RecordTypeProtobufToIR(record_type_protobuf);
    327     if (!IsPresentInExportedHeaders(record_type_ir, exported_headers_)) {
    328       continue;
    329     }
    330     auto it = AddToMapAndTypeGraph(std::move(record_type_ir), &record_types_,
    331                                    &type_graph_);
    332     const std::string &key = GetODRListMapKey(&(it->second));
    333     AddToODRListMap(key, &(it->second));
    334   }
    335 }
    336 
    337 void ProtobufTextFormatToIRReader::ReadFunctionTypes(
    338     const abi_dump::TranslationUnit &tu) {
    339   for (auto &&function_type_protobuf : tu.function_types()) {
    340     FunctionTypeIR function_type_ir =
    341         FunctionTypeProtobufToIR(function_type_protobuf);
    342     if (!IsPresentInExportedHeaders(function_type_ir, exported_headers_)) {
    343       continue;
    344     }
    345     auto it = AddToMapAndTypeGraph(std::move(function_type_ir),
    346                                    &function_types_, &type_graph_);
    347     const std::string &key = GetODRListMapKey(&(it->second));
    348     AddToODRListMap(key, &(it->second));
    349   }
    350 }
    351 
    352 void ProtobufTextFormatToIRReader::ReadEnumTypes(
    353     const abi_dump::TranslationUnit &tu) {
    354   for (auto &&enum_type_protobuf : tu.enum_types()) {
    355     EnumTypeIR enum_type_ir = EnumTypeProtobufToIR(enum_type_protobuf);
    356     if (!IsPresentInExportedHeaders(enum_type_ir, exported_headers_)) {
    357       continue;
    358     }
    359     auto it = AddToMapAndTypeGraph(std::move(enum_type_ir), &enum_types_,
    360                                    &type_graph_);
    361     AddToODRListMap(it->second.GetUniqueId() + it->second.GetSourceFile(),
    362                     (&it->second));
    363   }
    364 }
    365 
    366 void ProtobufTextFormatToIRReader::ReadElfFunctions(
    367     const abi_dump::TranslationUnit &tu) {
    368   for (auto &&elf_function : tu.elf_functions()) {
    369     ElfFunctionIR elf_function_ir(elf_function.name());
    370     elf_functions_.insert(
    371         {elf_function_ir.GetName(), std::move(elf_function_ir)});
    372   }
    373 }
    374 
    375 void ProtobufTextFormatToIRReader::ReadElfObjects(
    376     const abi_dump::TranslationUnit &tu) {
    377   for (auto &&elf_object : tu.elf_objects()) {
    378     ElfObjectIR elf_object_ir(elf_object.name());
    379     elf_objects_.insert(
    380         {elf_object_ir.GetName(), std::move(elf_object_ir)});
    381   }
    382 }
    383 
    384 bool IRToProtobufConverter::AddTemplateInformation(
    385     abi_dump::TemplateInfo *ti, const abi_util::TemplatedArtifactIR *ta) {
    386   for (auto &&template_element : ta->GetTemplateElements()) {
    387     abi_dump::TemplateElement *added_element = ti->add_elements();
    388     if (!added_element) {
    389       llvm::errs() << "Failed to add template element\n";
    390       return false;
    391     }
    392     added_element->set_referenced_type(template_element.GetReferencedType());
    393   }
    394   return true;
    395 }
    396 
    397 bool IRToProtobufConverter::AddTypeInfo(
    398     abi_dump::BasicNamedAndTypedDecl *type_info,
    399     const TypeIR *typep) {
    400   if (!type_info || !typep) {
    401     llvm::errs() << "Typeinfo not valid\n";
    402     return false;
    403   }
    404   type_info->set_linker_set_key(typep->GetLinkerSetKey());
    405   type_info->set_source_file(typep->GetSourceFile());
    406   type_info->set_name(typep->GetName());
    407   type_info->set_size(typep->GetSize());
    408   type_info->set_alignment(typep->GetAlignment());
    409   type_info->set_referenced_type(typep->GetReferencedType());
    410   type_info->set_self_type(typep->GetSelfType());
    411   return true;
    412 }
    413 
    414 static void SetIRToProtobufRecordField(
    415     abi_dump::RecordFieldDecl *record_field_protobuf,
    416     const RecordFieldIR *record_field_ir) {
    417   record_field_protobuf->set_field_name(record_field_ir->GetName());
    418   record_field_protobuf->set_referenced_type(
    419       record_field_ir->GetReferencedType());
    420   record_field_protobuf->set_access(
    421       AccessIRToProtobuf(record_field_ir->GetAccess()));
    422   record_field_protobuf->set_field_offset(record_field_ir->GetOffset());
    423 }
    424 
    425 bool IRToProtobufConverter::AddRecordFields(
    426     abi_dump::RecordType *record_protobuf,
    427     const RecordTypeIR *record_ir) {
    428   // Iterate through the fields and create corresponding ones for the protobuf
    429   // record
    430   for (auto &&field_ir : record_ir->GetFields()) {
    431     abi_dump::RecordFieldDecl *added_field = record_protobuf->add_fields();
    432     if (!added_field) {
    433       llvm::errs() << "Couldn't add record field\n";
    434     }
    435     SetIRToProtobufRecordField(added_field, &field_ir);
    436   }
    437   return true;
    438 }
    439 
    440 static bool SetIRToProtobufBaseSpecifier(
    441     abi_dump::CXXBaseSpecifier *base_specifier_protobuf,
    442     const CXXBaseSpecifierIR &base_specifier_ir) {
    443   if (!base_specifier_protobuf) {
    444     llvm::errs() << "Protobuf base specifier not valid\n";
    445     return false;
    446   }
    447   base_specifier_protobuf->set_referenced_type(
    448       base_specifier_ir.GetReferencedType());
    449   base_specifier_protobuf->set_is_virtual(
    450       base_specifier_ir.IsVirtual());
    451   base_specifier_protobuf->set_access(
    452       AccessIRToProtobuf(base_specifier_ir.GetAccess()));
    453   return true;
    454 }
    455 
    456 bool IRToProtobufConverter::AddBaseSpecifiers(
    457     abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir) {
    458   for (auto &&base_ir : record_ir->GetBases()) {
    459     abi_dump::CXXBaseSpecifier *added_base =
    460         record_protobuf->add_base_specifiers();
    461     if (!SetIRToProtobufBaseSpecifier(added_base, base_ir)) {
    462       return false;
    463     }
    464   }
    465   return true;
    466 }
    467 
    468 static bool SetIRToProtobufVTableLayout(
    469     abi_dump::VTableLayout *vtable_layout_protobuf,
    470     const VTableLayoutIR &vtable_layout_ir) {
    471   if (vtable_layout_protobuf == nullptr) {
    472     llvm::errs() << "vtable layout protobuf not valid\n";
    473     return false;
    474   }
    475   for (auto &&vtable_component_ir : vtable_layout_ir.GetVTableComponents()) {
    476     abi_dump::VTableComponent *added_vtable_component =
    477         vtable_layout_protobuf->add_vtable_components();
    478     if (!added_vtable_component) {
    479       llvm::errs() << "Couldn't add vtable component\n";
    480       return false;
    481     }
    482     added_vtable_component->set_kind(
    483         VTableComponentKindIRToProtobuf(vtable_component_ir.GetKind()));
    484     added_vtable_component->set_component_value(vtable_component_ir.GetValue());
    485     added_vtable_component->set_mangled_component_name(
    486         vtable_component_ir.GetName());
    487   }
    488   return true;
    489 }
    490 
    491 bool IRToProtobufConverter::AddVTableLayout(
    492     abi_dump::RecordType *record_protobuf,
    493     const RecordTypeIR *record_ir) {
    494   // If there are no entries in the vtable, just return.
    495   if (record_ir->GetVTableNumEntries() == 0) {
    496     return true;
    497   }
    498   const VTableLayoutIR &vtable_layout_ir = record_ir->GetVTableLayout();
    499   abi_dump::VTableLayout *vtable_layout_protobuf =
    500       record_protobuf->mutable_vtable_layout();
    501   if (!SetIRToProtobufVTableLayout(vtable_layout_protobuf, vtable_layout_ir)) {
    502     return false;
    503   }
    504   return true;
    505 }
    506 
    507 bool IRToProtobufConverter::AddTagTypeInfo(
    508     abi_dump::TagType *tag_type_protobuf,
    509     const abi_util::TagTypeIR *tag_type_ir) {
    510   if (!tag_type_protobuf || !tag_type_ir) {
    511     return false;
    512   }
    513   tag_type_protobuf->set_unique_id(tag_type_ir->GetUniqueId());
    514   return true;
    515 }
    516 
    517 abi_dump::RecordType IRToProtobufConverter::ConvertRecordTypeIR(
    518     const RecordTypeIR *recordp) {
    519   abi_dump::RecordType added_record_type;
    520   added_record_type.set_access(AccessIRToProtobuf(recordp->GetAccess()));
    521   added_record_type.set_record_kind(
    522       RecordKindIRToProtobuf(recordp->GetRecordKind()));
    523   if (recordp->IsAnonymous()) {
    524     added_record_type.set_is_anonymous(true);
    525   }
    526   if (!AddTypeInfo(added_record_type.mutable_type_info(), recordp) ||
    527       !AddRecordFields(&added_record_type, recordp) ||
    528       !AddBaseSpecifiers(&added_record_type, recordp) ||
    529       !AddVTableLayout(&added_record_type, recordp) ||
    530       !AddTagTypeInfo(added_record_type.mutable_tag_info(), recordp) ||
    531       !(recordp->GetTemplateElements().size() ?
    532        AddTemplateInformation(added_record_type.mutable_template_info(),
    533                               recordp) : true)) {
    534     llvm::errs() << "Template information could not be added\n";
    535     ::exit(1);
    536   }
    537   return added_record_type;
    538 }
    539 
    540 
    541 abi_dump::ElfObject IRToProtobufConverter::ConvertElfObjectIR(
    542     const ElfObjectIR *elf_object_ir) {
    543   abi_dump::ElfObject elf_object_protobuf;
    544   elf_object_protobuf.set_name(elf_object_ir->GetName());
    545   return elf_object_protobuf;
    546 }
    547 
    548 abi_dump::ElfFunction IRToProtobufConverter::ConvertElfFunctionIR(
    549     const ElfFunctionIR *elf_function_ir) {
    550   abi_dump::ElfFunction elf_function_protobuf;
    551   elf_function_protobuf.set_name(elf_function_ir->GetName());
    552   return elf_function_protobuf;
    553 }
    554 
    555 template <typename CFunctionLikeMessage>
    556 bool IRToProtobufConverter::AddFunctionParametersAndSetReturnType(
    557     CFunctionLikeMessage *function_like_protobuf,
    558     const CFunctionLikeIR *cfunction_like_ir) {
    559   function_like_protobuf->set_return_type(cfunction_like_ir->GetReturnType());
    560   return AddFunctionParameters(function_like_protobuf, cfunction_like_ir);
    561 }
    562 
    563 template <typename CFunctionLikeMessage>
    564 bool IRToProtobufConverter::AddFunctionParameters(
    565     CFunctionLikeMessage *function_like_protobuf,
    566     const CFunctionLikeIR *cfunction_like_ir) {
    567   for (auto &&parameter : cfunction_like_ir->GetParameters()) {
    568     abi_dump::ParamDecl *added_parameter =
    569         function_like_protobuf->add_parameters();
    570     if (!added_parameter) {
    571       return false;
    572     }
    573     added_parameter->set_referenced_type(
    574         parameter.GetReferencedType());
    575     added_parameter->set_default_arg(parameter.GetIsDefault());
    576     added_parameter->set_is_this_ptr(parameter.GetIsThisPtr());
    577   }
    578   return true;
    579 }
    580 
    581 abi_dump::FunctionType IRToProtobufConverter::ConvertFunctionTypeIR (
    582     const FunctionTypeIR *function_typep) {
    583   abi_dump::FunctionType added_function_type;
    584   if (!AddTypeInfo(added_function_type.mutable_type_info(), function_typep) ||
    585       !AddFunctionParametersAndSetReturnType(&added_function_type,
    586                                              function_typep)) {
    587     llvm::errs() << "Could not convert FunctionTypeIR to protobuf\n";
    588     ::exit(1);
    589   }
    590   return added_function_type;
    591 }
    592 
    593 abi_dump::FunctionDecl IRToProtobufConverter::ConvertFunctionIR(
    594     const FunctionIR *functionp) {
    595   abi_dump::FunctionDecl added_function;
    596   added_function.set_access(AccessIRToProtobuf(functionp->GetAccess()));
    597   added_function.set_linker_set_key(functionp->GetLinkerSetKey());
    598   added_function.set_source_file(functionp->GetSourceFile());
    599   added_function.set_function_name(functionp->GetName());
    600   if (!AddFunctionParametersAndSetReturnType(&added_function, functionp) ||
    601       !(functionp->GetTemplateElements().size() ?
    602       AddTemplateInformation(added_function.mutable_template_info(), functionp)
    603       : true)) {
    604     llvm::errs() << "Template information could not be added\n";
    605     ::exit(1);
    606   }
    607   return added_function;
    608 }
    609 
    610 static bool SetIRToProtobufEnumField(
    611     abi_dump::EnumFieldDecl *enum_field_protobuf,
    612     const EnumFieldIR *enum_field_ir) {
    613   if (enum_field_protobuf == nullptr) {
    614     return true;
    615   }
    616   enum_field_protobuf->set_name(enum_field_ir->GetName());
    617   enum_field_protobuf->set_enum_field_value(enum_field_ir->GetValue());
    618   return true;
    619 }
    620 
    621 bool IRToProtobufConverter::AddEnumFields(abi_dump::EnumType *enum_protobuf,
    622                                      const EnumTypeIR *enum_ir) {
    623   for (auto &&field : enum_ir->GetFields()) {
    624     abi_dump::EnumFieldDecl *enum_fieldp = enum_protobuf->add_enum_fields();
    625     if (!SetIRToProtobufEnumField(enum_fieldp, &field)) {
    626       return false;
    627     }
    628   }
    629   return true;
    630 }
    631 
    632 
    633 abi_dump::EnumType IRToProtobufConverter::ConvertEnumTypeIR(
    634     const EnumTypeIR *enump) {
    635   abi_dump::EnumType added_enum_type;
    636   added_enum_type.set_access(AccessIRToProtobuf(enump->GetAccess()));
    637   added_enum_type.set_underlying_type(enump->GetUnderlyingType());
    638   if (!AddTypeInfo(added_enum_type.mutable_type_info(), enump) ||
    639       !AddEnumFields(&added_enum_type, enump) ||
    640       !AddTagTypeInfo(added_enum_type.mutable_tag_info(), enump)) {
    641     llvm::errs() << "EnumTypeIR could not be converted\n";
    642     ::exit(1);
    643   }
    644   return added_enum_type;
    645 }
    646 
    647 abi_dump::GlobalVarDecl IRToProtobufConverter::ConvertGlobalVarIR(
    648     const GlobalVarIR *global_varp) {
    649   abi_dump::GlobalVarDecl added_global_var;
    650   added_global_var.set_referenced_type(global_varp->GetReferencedType());
    651   added_global_var.set_source_file(global_varp->GetSourceFile());
    652   added_global_var.set_name(global_varp->GetName());
    653   added_global_var.set_linker_set_key(global_varp->GetLinkerSetKey());
    654   added_global_var.set_access(
    655       AccessIRToProtobuf(global_varp->GetAccess()));
    656   return added_global_var;
    657 }
    658 
    659 abi_dump::PointerType IRToProtobufConverter::ConvertPointerTypeIR(
    660     const PointerTypeIR *pointerp) {
    661   abi_dump::PointerType added_pointer_type;
    662   if (!AddTypeInfo(added_pointer_type.mutable_type_info(), pointerp)) {
    663     llvm::errs() << "PointerTypeIR could not be converted\n";
    664     ::exit(1);
    665   }
    666   return added_pointer_type;
    667 }
    668 
    669 abi_dump::QualifiedType IRToProtobufConverter::ConvertQualifiedTypeIR(
    670     const QualifiedTypeIR *qualtypep) {
    671   abi_dump::QualifiedType added_qualified_type;
    672   if (!AddTypeInfo(added_qualified_type.mutable_type_info(), qualtypep)) {
    673     llvm::errs() << "QualifiedTypeIR could not be converted\n";
    674     ::exit(1);
    675   }
    676   added_qualified_type.set_is_const(qualtypep->IsConst());
    677   added_qualified_type.set_is_volatile(qualtypep->IsVolatile());
    678   added_qualified_type.set_is_restricted(qualtypep->IsRestricted());
    679   return added_qualified_type;
    680 }
    681 
    682 abi_dump::BuiltinType IRToProtobufConverter::ConvertBuiltinTypeIR(
    683     const BuiltinTypeIR *builtin_typep) {
    684   abi_dump::BuiltinType added_builtin_type;
    685   added_builtin_type.set_is_unsigned(builtin_typep->IsUnsigned());
    686   added_builtin_type.set_is_integral(builtin_typep->IsIntegralType());
    687   if (!AddTypeInfo(added_builtin_type.mutable_type_info(), builtin_typep)) {
    688     llvm::errs() << "BuiltinTypeIR could not be converted\n";
    689     ::exit(1);
    690   }
    691   return added_builtin_type;
    692 }
    693 
    694 abi_dump::ArrayType IRToProtobufConverter::ConvertArrayTypeIR(
    695     const ArrayTypeIR *array_typep) {
    696   abi_dump::ArrayType added_array_type;
    697   if (!AddTypeInfo(added_array_type.mutable_type_info(), array_typep)) {
    698     llvm::errs() << "ArrayTypeIR could not be converted\n";
    699     ::exit(1);
    700   }
    701   return added_array_type;
    702 }
    703 
    704 abi_dump::LvalueReferenceType
    705 IRToProtobufConverter::ConvertLvalueReferenceTypeIR(
    706     const LvalueReferenceTypeIR *lvalue_reference_typep) {
    707   abi_dump::LvalueReferenceType added_lvalue_reference_type;
    708   if (!AddTypeInfo(added_lvalue_reference_type.mutable_type_info(),
    709                    lvalue_reference_typep)) {
    710     llvm::errs() << "LvalueReferenceTypeIR could not be converted\n";
    711     ::exit(1);
    712   }
    713   return added_lvalue_reference_type;
    714 }
    715 
    716 abi_dump::RvalueReferenceType
    717 IRToProtobufConverter::ConvertRvalueReferenceTypeIR(
    718     const RvalueReferenceTypeIR *rvalue_reference_typep) {
    719   abi_dump::RvalueReferenceType added_rvalue_reference_type;
    720   if (!AddTypeInfo(added_rvalue_reference_type.mutable_type_info(),
    721                    rvalue_reference_typep)) {
    722     llvm::errs() << "RvalueReferenceTypeIR could not be converted\n";
    723     ::exit(1);
    724   }
    725   return added_rvalue_reference_type;
    726 }
    727 
    728 
    729 bool IRDiffToProtobufConverter::AddTypeInfoDiff(
    730     abi_diff::TypeInfoDiff *type_info_diff_protobuf,
    731     const TypeDiffIR *type_diff_ir) {
    732   abi_diff::TypeInfo *old_type_info_protobuf =
    733       type_info_diff_protobuf->mutable_old_type_info();
    734   abi_diff::TypeInfo *new_type_info_protobuf =
    735       type_info_diff_protobuf->mutable_new_type_info();
    736   if (old_type_info_protobuf == nullptr || new_type_info_protobuf == nullptr) {
    737     return false;
    738   }
    739   const std::pair<uint64_t, uint64_t> &sizes = type_diff_ir->GetSizes();
    740   const std::pair<uint32_t, uint32_t> &alignments =
    741       type_diff_ir->GetAlignments();
    742   old_type_info_protobuf->set_size(sizes.first);
    743   new_type_info_protobuf->set_size(sizes.second);
    744 
    745   old_type_info_protobuf->set_alignment(alignments.first);
    746   new_type_info_protobuf->set_alignment(alignments.second);
    747   return true;
    748 }
    749 
    750 bool IRDiffToProtobufConverter::AddVTableLayoutDiff(
    751     abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf,
    752     const VTableLayoutDiffIR *vtable_layout_diff_ir) {
    753   abi_dump:: VTableLayout *old_vtable =
    754       vtable_layout_diff_protobuf->mutable_old_vtable();
    755   abi_dump:: VTableLayout *new_vtable =
    756       vtable_layout_diff_protobuf->mutable_new_vtable();
    757   if (old_vtable == nullptr || new_vtable == nullptr ||
    758       !SetIRToProtobufVTableLayout(old_vtable,
    759                                    vtable_layout_diff_ir->GetOldVTable()) ||
    760       !SetIRToProtobufVTableLayout(new_vtable,
    761                                    vtable_layout_diff_ir->GetNewVTable())) {
    762     return false;
    763   }
    764   return true;
    765 }
    766 
    767 template <typename T>
    768 static bool CopyBaseSpecifiersDiffIRToProtobuf(
    769     google::protobuf::RepeatedPtrField<T> *dst,
    770     const std::vector<CXXBaseSpecifierIR> &bases_ir) {
    771   for (auto &&base_ir : bases_ir) {
    772     T *added_base = dst->Add();
    773     if (!SetIRToProtobufBaseSpecifier(added_base, base_ir)) {
    774       return false;
    775     }
    776   }
    777   return true;
    778 }
    779 
    780 bool IRDiffToProtobufConverter::AddBaseSpecifierDiffs(
    781     abi_diff::CXXBaseSpecifierDiff *base_specifiers_diff_protobuf,
    782     const CXXBaseSpecifierDiffIR *base_specifiers_diff_ir) {
    783   if (!CopyBaseSpecifiersDiffIRToProtobuf(
    784           base_specifiers_diff_protobuf->mutable_old_bases(),
    785           base_specifiers_diff_ir->GetOldBases()) ||
    786       !CopyBaseSpecifiersDiffIRToProtobuf(
    787           base_specifiers_diff_protobuf->mutable_new_bases(),
    788           base_specifiers_diff_ir->GetNewBases())) {
    789     return false;
    790   }
    791   return true;
    792 }
    793 
    794 bool IRDiffToProtobufConverter::AddRecordFields(
    795     abi_diff::RecordTypeDiff *record_diff_protobuf,
    796     const std::vector<const RecordFieldIR *> &record_fields_ir,
    797     bool field_removed) {
    798   for (auto &&record_field_ir : record_fields_ir) {
    799     abi_dump::RecordFieldDecl *field = nullptr;
    800     if (field_removed) {
    801       field = record_diff_protobuf->add_fields_removed();
    802     } else {
    803       field = record_diff_protobuf->add_fields_added();
    804     }
    805     if (field == nullptr) {
    806       return false;
    807     }
    808     SetIRToProtobufRecordField(field, record_field_ir);
    809   }
    810   return true;
    811 }
    812 
    813 bool IRDiffToProtobufConverter::AddRecordFieldDiffs(
    814     abi_diff::RecordTypeDiff *record_diff_protobuf,
    815     const std::vector<RecordFieldDiffIR> &record_field_diffs_ir) {
    816   for (auto &&record_field_diff_ir : record_field_diffs_ir) {
    817     abi_diff::RecordFieldDeclDiff *record_field_diff =
    818         record_diff_protobuf->add_fields_diff();
    819     if (record_field_diff == nullptr) {
    820       return false;
    821     }
    822     abi_dump::RecordFieldDecl *old_field =
    823         record_field_diff->mutable_old_field();
    824     abi_dump::RecordFieldDecl *new_field =
    825         record_field_diff->mutable_new_field();
    826     if (old_field == nullptr || new_field == nullptr) {
    827       return false;
    828     }
    829     SetIRToProtobufRecordField(old_field,
    830                                record_field_diff_ir.GetOldField());
    831     SetIRToProtobufRecordField(new_field,
    832                                record_field_diff_ir.GetNewField());
    833   }
    834   return true;
    835 }
    836 
    837 abi_diff::RecordTypeDiff IRDiffToProtobufConverter::ConvertRecordTypeDiffIR(
    838     const RecordTypeDiffIR *record_type_diff_ir) {
    839   abi_diff::RecordTypeDiff record_type_diff_protobuf;
    840   record_type_diff_protobuf.set_name(record_type_diff_ir->GetName());
    841   const TypeDiffIR *type_diff_ir = record_type_diff_ir->GetTypeDiff();
    842   // If a type_info diff exists
    843   if (type_diff_ir != nullptr) {
    844     abi_diff::TypeInfoDiff *type_info_diff =
    845         record_type_diff_protobuf.mutable_type_info_diff();
    846     if (!AddTypeInfoDiff(type_info_diff, type_diff_ir)) {
    847         llvm::errs() << "RecordType could not be converted\n";
    848        ::exit(1);
    849     }
    850   }
    851   // If vtables differ.
    852   const VTableLayoutDiffIR *vtable_layout_diff_ir =
    853       record_type_diff_ir->GetVTableLayoutDiff();
    854   if (vtable_layout_diff_ir != nullptr) {
    855     abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf =
    856         record_type_diff_protobuf.mutable_vtable_layout_diff();
    857     if (!AddVTableLayoutDiff(vtable_layout_diff_protobuf,
    858                              vtable_layout_diff_ir)) {
    859       llvm::errs() << "VTable layout diff could not be added\n";
    860       ::exit(1);
    861     }
    862   }
    863   // If base specifiers differ.
    864   const CXXBaseSpecifierDiffIR *base_specifier_diff_ir =
    865       record_type_diff_ir->GetBaseSpecifiers();
    866   if ( base_specifier_diff_ir != nullptr) {
    867     abi_diff::CXXBaseSpecifierDiff *base_specifier_diff_protobuf =
    868         record_type_diff_protobuf.mutable_bases_diff();
    869     if (!AddBaseSpecifierDiffs(base_specifier_diff_protobuf,
    870                                base_specifier_diff_ir)) {
    871       llvm::errs() << "Base Specifier diff could not be added\n";
    872       ::exit(1);
    873     }
    874   }
    875   // Field diffs
    876   if (!AddRecordFields(&record_type_diff_protobuf,
    877                        record_type_diff_ir->GetFieldsRemoved(), true) ||
    878       !AddRecordFields(&record_type_diff_protobuf,
    879                        record_type_diff_ir->GetFieldsAdded(), false) ||
    880       !AddRecordFieldDiffs(&record_type_diff_protobuf,
    881                            record_type_diff_ir->GetFieldDiffs())) {
    882     llvm::errs() << "Record Field diff could not be added\n";
    883     ::exit(1);
    884   }
    885   return record_type_diff_protobuf;
    886 }
    887 
    888 bool IRDiffToProtobufConverter::AddEnumUnderlyingTypeDiff(
    889     abi_diff::UnderlyingTypeDiff *underlying_type_diff_protobuf,
    890     const std::pair<std::string, std::string> *underlying_type_diff_ir) {
    891   if (underlying_type_diff_protobuf == nullptr) {
    892     return false;
    893   }
    894   underlying_type_diff_protobuf->set_old_type(underlying_type_diff_ir->first);
    895   underlying_type_diff_protobuf->set_new_type(underlying_type_diff_ir->second);
    896   return true;
    897 }
    898 
    899 static bool AddEnumFields(
    900     google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> *dst,
    901     const std::vector<const EnumFieldIR *> &enum_fields) {
    902   for (auto &&enum_field : enum_fields) {
    903     abi_dump::EnumFieldDecl *added_enum_field = dst->Add();
    904     if (!SetIRToProtobufEnumField(added_enum_field, enum_field)) {
    905       return false;
    906     }
    907   }
    908   return true;
    909 }
    910 
    911 static bool AddEnumFieldDiffs(
    912     google::protobuf::RepeatedPtrField<abi_diff::EnumFieldDeclDiff> *dst,
    913     const std::vector<EnumFieldDiffIR> &fields_diff_ir) {
    914   for (auto &&field_diff_ir : fields_diff_ir) {
    915     abi_diff::EnumFieldDeclDiff *field_diff_protobuf = dst->Add();
    916     if (field_diff_protobuf == nullptr) {
    917       return false;
    918     }
    919     if (!SetIRToProtobufEnumField(field_diff_protobuf->mutable_old_field(),
    920                                   field_diff_ir.GetOldField()) ||
    921         !SetIRToProtobufEnumField(field_diff_protobuf->mutable_new_field(),
    922                                   field_diff_ir.GetNewField())) {
    923       return false;
    924     }
    925   }
    926   return true;
    927 }
    928 
    929 abi_diff::EnumTypeDiff IRDiffToProtobufConverter::ConvertEnumTypeDiffIR(
    930     const EnumTypeDiffIR *enum_type_diff_ir) {
    931   abi_diff::EnumTypeDiff enum_type_diff_protobuf;
    932   enum_type_diff_protobuf.set_name(enum_type_diff_ir->GetName());
    933   const std::pair<std::string, std::string> *underlying_type_diff =
    934       enum_type_diff_ir->GetUnderlyingTypeDiff();
    935   if ((underlying_type_diff != nullptr &&
    936       !AddEnumUnderlyingTypeDiff(
    937           enum_type_diff_protobuf.mutable_underlying_type_diff(),
    938           underlying_type_diff)) ||
    939       !AddEnumFields(enum_type_diff_protobuf.mutable_fields_removed(),
    940                      enum_type_diff_ir->GetFieldsRemoved()) ||
    941       !AddEnumFields(enum_type_diff_protobuf.mutable_fields_added(),
    942                      enum_type_diff_ir->GetFieldsAdded()) ||
    943       !AddEnumFieldDiffs(enum_type_diff_protobuf.mutable_fields_diff(),
    944                          enum_type_diff_ir->GetFieldsDiff())) {
    945     llvm::errs() << "Enum field diff could not be added\n";
    946     ::exit(1);
    947   }
    948   return enum_type_diff_protobuf;
    949 }
    950 
    951 abi_diff::GlobalVarDeclDiff IRDiffToProtobufConverter::ConvertGlobalVarDiffIR(
    952     const GlobalVarDiffIR *global_var_diff_ir) {
    953   abi_diff::GlobalVarDeclDiff global_var_diff;
    954   global_var_diff.set_name(global_var_diff_ir->GetName());
    955   abi_dump::GlobalVarDecl *old_global_var = global_var_diff.mutable_old();
    956   abi_dump::GlobalVarDecl *new_global_var = global_var_diff.mutable_new_();
    957   if (old_global_var == nullptr || new_global_var == nullptr) {
    958     llvm::errs() << "Globar Var diff could not be added\n";
    959     ::exit(1);
    960   }
    961   *old_global_var =
    962       IRToProtobufConverter::ConvertGlobalVarIR(
    963           global_var_diff_ir->GetOldGlobalVar());
    964   *new_global_var =
    965       IRToProtobufConverter::ConvertGlobalVarIR(
    966           global_var_diff_ir->GetNewGlobalVar());
    967   return global_var_diff;
    968 }
    969 
    970 abi_diff::FunctionDeclDiff IRDiffToProtobufConverter::ConvertFunctionDiffIR(
    971     const FunctionDiffIR *function_diff_ir) {
    972   abi_diff::FunctionDeclDiff function_diff;
    973   function_diff.set_name(function_diff_ir->GetName());
    974   abi_dump::FunctionDecl *old_function = function_diff.mutable_old();
    975   abi_dump::FunctionDecl *new_function = function_diff.mutable_new_();
    976   if (old_function == nullptr || new_function == nullptr) {
    977     llvm::errs() << "Function diff could not be added\n";
    978     ::exit(1);
    979   }
    980   *old_function =
    981       IRToProtobufConverter::ConvertFunctionIR(
    982           function_diff_ir->GetOldFunction());
    983   *new_function =
    984       IRToProtobufConverter::ConvertFunctionIR(
    985           function_diff_ir->GetNewFunction());
    986   return function_diff;
    987 }
    988 
    989 bool ProtobufIRDumper::AddLinkableMessageIR (const LinkableMessageIR *lm) {
    990   // No RTTI
    991   switch (lm->GetKind()) {
    992     case RecordTypeKind:
    993       return AddRecordTypeIR(static_cast<const RecordTypeIR *>(lm));
    994     case EnumTypeKind:
    995       return AddEnumTypeIR(static_cast<const EnumTypeIR *>(lm));
    996     case PointerTypeKind:
    997       return AddPointerTypeIR(static_cast<const PointerTypeIR *>(lm));
    998     case QualifiedTypeKind:
    999       return AddQualifiedTypeIR(static_cast<const QualifiedTypeIR *>(lm));
   1000     case ArrayTypeKind:
   1001       return AddArrayTypeIR(static_cast<const ArrayTypeIR *>(lm));
   1002     case LvalueReferenceTypeKind:
   1003       return AddLvalueReferenceTypeIR(
   1004           static_cast<const LvalueReferenceTypeIR *>(lm));
   1005     case RvalueReferenceTypeKind:
   1006       return AddRvalueReferenceTypeIR(
   1007           static_cast<const RvalueReferenceTypeIR*>(lm));
   1008     case BuiltinTypeKind:
   1009       return AddBuiltinTypeIR(static_cast<const BuiltinTypeIR*>(lm));
   1010     case FunctionTypeKind:
   1011       return AddFunctionTypeIR(static_cast<const FunctionTypeIR*>(lm));
   1012     case GlobalVarKind:
   1013       return AddGlobalVarIR(static_cast<const GlobalVarIR*>(lm));
   1014     case FunctionKind:
   1015       return AddFunctionIR(static_cast<const FunctionIR*>(lm));
   1016   }
   1017   return false;
   1018 }
   1019 
   1020 bool ProtobufIRDumper::AddElfFunctionIR(const ElfFunctionIR *elf_function) {
   1021   abi_dump::ElfFunction *added_elf_function = tu_ptr_->add_elf_functions();
   1022   if (!added_elf_function) {
   1023     return false;
   1024   }
   1025   added_elf_function->set_name(elf_function->GetName());
   1026   return true;
   1027 }
   1028 
   1029 bool ProtobufIRDumper::AddElfObjectIR(const ElfObjectIR *elf_object) {
   1030   abi_dump::ElfObject *added_elf_object = tu_ptr_->add_elf_objects();
   1031   if (!added_elf_object) {
   1032     return false;
   1033   }
   1034   added_elf_object->set_name(elf_object->GetName());
   1035   return true;
   1036 }
   1037 
   1038 bool ProtobufIRDumper::AddElfSymbolMessageIR(const ElfSymbolIR *em) {
   1039   switch (em->GetKind()) {
   1040     case ElfSymbolIR::ElfFunctionKind:
   1041       return AddElfFunctionIR(static_cast<const ElfFunctionIR *>(em));
   1042     case ElfSymbolIR::ElfObjectKind:
   1043       return AddElfObjectIR(static_cast<const ElfObjectIR *>(em));
   1044   }
   1045   return false;
   1046 }
   1047 
   1048 bool ProtobufIRDumper::AddRecordTypeIR(const RecordTypeIR *recordp) {
   1049   abi_dump::RecordType *added_record_type = tu_ptr_->add_record_types();
   1050   if (!added_record_type) {
   1051     return false;
   1052   }
   1053   *added_record_type = ConvertRecordTypeIR(recordp);
   1054   return true;
   1055 }
   1056 
   1057 bool ProtobufIRDumper::AddFunctionTypeIR(const FunctionTypeIR *function_typep) {
   1058   abi_dump::FunctionType *added_function_type = tu_ptr_->add_function_types();
   1059   if (!added_function_type) {
   1060     return false;
   1061   }
   1062   *added_function_type = ConvertFunctionTypeIR(function_typep);
   1063   return true;
   1064 }
   1065 
   1066 bool ProtobufIRDumper::AddFunctionIR(const FunctionIR *functionp) {
   1067   abi_dump::FunctionDecl *added_function = tu_ptr_->add_functions();
   1068   if (!added_function) {
   1069     return false;
   1070   }
   1071   *added_function = ConvertFunctionIR(functionp);
   1072   return true;
   1073 }
   1074 
   1075 bool ProtobufIRDumper::AddEnumTypeIR(const EnumTypeIR *enump) {
   1076   abi_dump::EnumType *added_enum_type = tu_ptr_->add_enum_types();
   1077   if (!added_enum_type) {
   1078     return false;
   1079   }
   1080   *added_enum_type = ConvertEnumTypeIR(enump);
   1081   return true;
   1082 }
   1083 
   1084 bool ProtobufIRDumper::AddGlobalVarIR(const GlobalVarIR *global_varp) {
   1085   abi_dump::GlobalVarDecl *added_global_var = tu_ptr_->add_global_vars();
   1086   if (!added_global_var) {
   1087     return false;
   1088   }
   1089   *added_global_var = ConvertGlobalVarIR(global_varp);
   1090   return true;
   1091 }
   1092 
   1093 bool ProtobufIRDumper::AddPointerTypeIR(const PointerTypeIR *pointerp) {
   1094   abi_dump::PointerType *added_pointer_type = tu_ptr_->add_pointer_types();
   1095   if (!added_pointer_type) {
   1096     return false;
   1097   }
   1098   *added_pointer_type = ConvertPointerTypeIR(pointerp);
   1099   return true;
   1100 }
   1101 
   1102 bool ProtobufIRDumper::AddQualifiedTypeIR(const QualifiedTypeIR *qualtypep) {
   1103   abi_dump::QualifiedType *added_qualified_type =
   1104       tu_ptr_->add_qualified_types();
   1105   if (!added_qualified_type) {
   1106     return false;
   1107   }
   1108   *added_qualified_type = ConvertQualifiedTypeIR(qualtypep);
   1109   return true;
   1110 }
   1111 
   1112 bool ProtobufIRDumper::AddBuiltinTypeIR(const BuiltinTypeIR *builtin_typep) {
   1113   abi_dump::BuiltinType *added_builtin_type =
   1114       tu_ptr_->add_builtin_types();
   1115   if (!added_builtin_type) {
   1116     return false;
   1117   }
   1118   *added_builtin_type = ConvertBuiltinTypeIR(builtin_typep);
   1119   return true;
   1120 }
   1121 
   1122 bool ProtobufIRDumper::AddArrayTypeIR(const ArrayTypeIR *array_typep) {
   1123   abi_dump::ArrayType *added_array_type =
   1124       tu_ptr_->add_array_types();
   1125   if (!added_array_type) {
   1126     return false;
   1127   }
   1128   *added_array_type = ConvertArrayTypeIR(array_typep);
   1129   return true;
   1130 }
   1131 
   1132 bool ProtobufIRDumper::AddLvalueReferenceTypeIR(
   1133     const LvalueReferenceTypeIR *lvalue_reference_typep) {
   1134   abi_dump::LvalueReferenceType *added_lvalue_reference_type =
   1135       tu_ptr_->add_lvalue_reference_types();
   1136   if (!added_lvalue_reference_type) {
   1137     return false;
   1138   }
   1139   *added_lvalue_reference_type =
   1140       ConvertLvalueReferenceTypeIR(lvalue_reference_typep);
   1141   return true;
   1142 }
   1143 
   1144 bool ProtobufIRDumper::AddRvalueReferenceTypeIR(
   1145     const RvalueReferenceTypeIR *rvalue_reference_typep) {
   1146   abi_dump::RvalueReferenceType *added_rvalue_reference_type =
   1147       tu_ptr_->add_rvalue_reference_types();
   1148   if (!added_rvalue_reference_type) {
   1149     return false;
   1150   }
   1151   *added_rvalue_reference_type =
   1152       ConvertRvalueReferenceTypeIR(rvalue_reference_typep);
   1153   return true;
   1154 }
   1155 
   1156 bool ProtobufIRDumper::Dump() {
   1157   GOOGLE_PROTOBUF_VERIFY_VERSION;
   1158   assert( tu_ptr_.get() != nullptr);
   1159   std::ofstream text_output(dump_path_);
   1160   google::protobuf::io::OstreamOutputStream text_os(&text_output);
   1161   return google::protobuf::TextFormat::Print(*tu_ptr_.get(), &text_os);
   1162 }
   1163 
   1164 void ProtobufIRDiffDumper::AddLibNameIR(const std::string &name) {
   1165   diff_tu_->set_lib_name(name);
   1166 }
   1167 
   1168 void ProtobufIRDiffDumper::AddArchIR(const std::string &arch) {
   1169   diff_tu_->set_arch(arch);
   1170 }
   1171 
   1172 CompatibilityStatusIR ProtobufIRDiffDumper::GetCompatibilityStatusIR() {
   1173   if (diff_tu_->functions_removed().size() != 0 ||
   1174       diff_tu_->global_vars_removed().size() != 0 ||
   1175       diff_tu_->function_diffs().size() != 0 ||
   1176       diff_tu_->global_var_diffs().size() != 0 ||
   1177       diff_tu_->enum_type_diffs().size() != 0 ||
   1178       diff_tu_->record_type_diffs().size() != 0) {
   1179     return CompatibilityStatusIR::Incompatible;
   1180   }
   1181 
   1182   CompatibilityStatusIR combined_status = CompatibilityStatusIR::Compatible;
   1183 
   1184   if (diff_tu_->enum_type_extension_diffs().size() != 0 ||
   1185       diff_tu_->functions_added().size() != 0 ||
   1186       diff_tu_->global_vars_added().size() != 0) {
   1187     combined_status = combined_status | CompatibilityStatusIR::Extension;
   1188   }
   1189 
   1190   if (diff_tu_->unreferenced_enum_type_diffs().size() != 0 ||
   1191       diff_tu_->unreferenced_enum_types_removed().size() != 0 ||
   1192       diff_tu_->unreferenced_record_types_removed().size() != 0 ||
   1193       diff_tu_->unreferenced_record_type_diffs().size() != 0 ||
   1194       diff_tu_->unreferenced_enum_type_extension_diffs().size() != 0 ||
   1195       diff_tu_->unreferenced_record_types_added().size() != 0 ||
   1196       diff_tu_->unreferenced_enum_types_added().size()) {
   1197     combined_status =
   1198         combined_status | CompatibilityStatusIR::UnreferencedChanges;
   1199   }
   1200 
   1201   if(diff_tu_->removed_elf_functions().size() != 0 ||
   1202      diff_tu_->removed_elf_objects().size() != 0) {
   1203     combined_status = combined_status | CompatibilityStatusIR::ElfIncompatible;
   1204   }
   1205 
   1206   return combined_status;
   1207 }
   1208 
   1209 void ProtobufIRDiffDumper::AddCompatibilityStatusIR(
   1210     CompatibilityStatusIR status) {
   1211   diff_tu_->set_compatibility_status(CompatibilityStatusIRToProtobuf(status));
   1212 }
   1213 
   1214 bool ProtobufIRDiffDumper::AddDiffMessageIR(
   1215     const DiffMessageIR *message,
   1216     const std::string &type_stack,
   1217     DiffKind diff_kind) {
   1218   switch (message->Kind()) {
   1219     case RecordTypeKind:
   1220       return AddRecordTypeDiffIR(
   1221           static_cast<const RecordTypeDiffIR *>(message),
   1222           type_stack, diff_kind);
   1223     case EnumTypeKind:
   1224       return AddEnumTypeDiffIR(
   1225           static_cast<const EnumTypeDiffIR *>(message),
   1226           type_stack, diff_kind);
   1227     case GlobalVarKind:
   1228       return AddGlobalVarDiffIR(
   1229           static_cast<const GlobalVarDiffIR*>(message),
   1230           type_stack, diff_kind);
   1231     case FunctionKind:
   1232       return AddFunctionDiffIR(
   1233           static_cast<const FunctionDiffIR*>(message),
   1234           type_stack, diff_kind);
   1235     default:
   1236       break;
   1237   }
   1238   llvm::errs() << "Dump Diff attempted on something not a user defined type" <<
   1239                    "/ function / global variable\n";
   1240   return false;
   1241 }
   1242 
   1243 bool ProtobufIRDiffDumper::AddLinkableMessageIR(
   1244     const LinkableMessageIR *message,
   1245     DiffKind diff_kind) {
   1246   switch (message->GetKind()) {
   1247     case RecordTypeKind:
   1248       return AddLoneRecordTypeDiffIR(
   1249           static_cast<const RecordTypeIR *>(message), diff_kind);
   1250     case EnumTypeKind:
   1251       return AddLoneEnumTypeDiffIR(
   1252           static_cast<const EnumTypeIR *>(message), diff_kind);
   1253     case GlobalVarKind:
   1254       return AddLoneGlobalVarDiffIR(
   1255           static_cast<const GlobalVarIR*>(message), diff_kind);
   1256     case FunctionKind:
   1257       return AddLoneFunctionDiffIR(
   1258           static_cast<const FunctionIR*>(message), diff_kind);
   1259     default:
   1260       break;
   1261   }
   1262   llvm::errs() << "Dump Diff attempted on something not a user defined type" <<
   1263                    "/ function / global variable\n";
   1264   return false;
   1265 }
   1266 
   1267 bool ProtobufIRDiffDumper::AddElfSymbolMessageIR (const ElfSymbolIR *elf_symbol,
   1268                                                   DiffKind diff_kind) {
   1269   switch (elf_symbol->GetKind()) {
   1270     case ElfSymbolIR::ElfFunctionKind:
   1271       return AddElfFunctionIR(static_cast<const ElfFunctionIR *>(elf_symbol),
   1272                               diff_kind);
   1273       break;
   1274     case ElfSymbolIR::ElfObjectKind:
   1275       return AddElfObjectIR(static_cast<const ElfObjectIR *>(elf_symbol),
   1276                             diff_kind);
   1277       break;
   1278   }
   1279   // Any other kind is invalid
   1280   return false;
   1281 }
   1282 
   1283 bool ProtobufIRDiffDumper::AddElfFunctionIR(
   1284     const ElfFunctionIR *elf_function_ir, DiffKind diff_kind) {
   1285   abi_dump::ElfFunction *added_elf_function = nullptr;
   1286   switch(diff_kind) {
   1287     case DiffKind::Removed:
   1288       added_elf_function = diff_tu_->add_removed_elf_functions();
   1289       break;
   1290     case DiffKind::Added:
   1291       added_elf_function = diff_tu_->add_added_elf_functions();
   1292       break;
   1293     default:
   1294       llvm::errs() << "Invalid call to AddElfFunctionIR\n";
   1295       return false;
   1296   }
   1297   if (added_elf_function == nullptr) {
   1298     return false;
   1299   }
   1300   *added_elf_function =
   1301       IRToProtobufConverter::ConvertElfFunctionIR(elf_function_ir);
   1302   return true;
   1303 }
   1304 
   1305 bool ProtobufIRDiffDumper::AddElfObjectIR(
   1306     const ElfObjectIR *elf_object_ir, DiffKind diff_kind) {
   1307   abi_dump::ElfObject *added_elf_object = nullptr;
   1308   switch(diff_kind) {
   1309     case DiffKind::Removed:
   1310       added_elf_object = diff_tu_->add_removed_elf_objects();
   1311       break;
   1312     case DiffKind::Added:
   1313       added_elf_object = diff_tu_->add_added_elf_objects();
   1314       break;
   1315     default:
   1316       llvm::errs() << "Invalid call to AddElfObjectIR\n";
   1317       return false;
   1318   }
   1319   if (added_elf_object == nullptr) {
   1320     return false;
   1321   }
   1322   *added_elf_object =
   1323       IRToProtobufConverter::ConvertElfObjectIR(elf_object_ir);
   1324   return true;
   1325 }
   1326 
   1327 bool ProtobufIRDiffDumper::AddLoneRecordTypeDiffIR(
   1328     const RecordTypeIR *record_type_ir,
   1329     DiffKind diff_kind) {
   1330   abi_dump::RecordType *added_record_type = nullptr;
   1331   switch (diff_kind) {
   1332     case DiffKind::Removed:
   1333       // Referenced record types do not get reported as added / removed,
   1334       // the diff shows up in the parent type / function/ global variable
   1335       // referencing the record.
   1336       added_record_type = diff_tu_->add_unreferenced_record_types_removed();
   1337       break;
   1338     case DiffKind::Added:
   1339       added_record_type = diff_tu_->add_unreferenced_record_types_added();
   1340       break;
   1341     default:
   1342       llvm::errs() << "Invalid call to AddLoneRecordTypeDiffIR\n";
   1343       return false;
   1344   }
   1345   if (added_record_type == nullptr) {
   1346     return false;
   1347   }
   1348   *added_record_type =
   1349       IRToProtobufConverter::ConvertRecordTypeIR(record_type_ir);
   1350   return true;
   1351 }
   1352 
   1353 bool ProtobufIRDiffDumper::AddLoneFunctionDiffIR(
   1354     const FunctionIR *function_ir,
   1355     DiffKind diff_kind) {
   1356   abi_dump::FunctionDecl *added_function = nullptr;
   1357   switch (diff_kind) {
   1358     case DiffKind::Removed:
   1359       added_function = diff_tu_->add_functions_removed();
   1360       break;
   1361     case DiffKind::Added:
   1362       added_function = diff_tu_->add_functions_added();
   1363       break;
   1364     default:
   1365       llvm::errs() << "Invalid call to AddLoneFunctionDiffIR\n";
   1366       return false;
   1367   }
   1368   *added_function = IRToProtobufConverter::ConvertFunctionIR(function_ir);
   1369   return true;
   1370 }
   1371 
   1372 bool ProtobufIRDiffDumper::AddLoneEnumTypeDiffIR(
   1373     const EnumTypeIR *enum_type_ir, DiffKind diff_kind) {
   1374   abi_dump::EnumType *added_enum_type = nullptr;
   1375   switch (diff_kind) {
   1376     case DiffKind::Removed:
   1377       // Referenced enum types do not get reported as added / removed,
   1378       // the diff shows up in the parent type / function/ global variable
   1379       // referencing the enum.
   1380       added_enum_type = diff_tu_->add_unreferenced_enum_types_removed();
   1381       break;
   1382     case DiffKind::Added:
   1383       added_enum_type = diff_tu_->add_unreferenced_enum_types_added();
   1384       break;
   1385     default:
   1386       llvm::errs() << "Invalid call to AddLoneRecordTypeDiffIR\n";
   1387       return false;
   1388   }
   1389   if (added_enum_type == nullptr) {
   1390     return false;
   1391   }
   1392   *added_enum_type = IRToProtobufConverter::ConvertEnumTypeIR(enum_type_ir);
   1393   return true;
   1394 }
   1395 
   1396 bool ProtobufIRDiffDumper::AddLoneGlobalVarDiffIR(
   1397     const GlobalVarIR *global_var_ir, DiffKind diff_kind) {
   1398   abi_dump::GlobalVarDecl *added_global_var = nullptr;
   1399   switch (diff_kind) {
   1400     case DiffKind::Removed:
   1401       added_global_var = diff_tu_->add_global_vars_removed();
   1402       break;
   1403     case DiffKind::Added:
   1404       added_global_var = diff_tu_->add_global_vars_added();
   1405       break;
   1406     default:
   1407       llvm::errs() << "Invalid call to AddLoneFunctionDiffIR\n";
   1408       return false;
   1409   }
   1410   *added_global_var = IRToProtobufConverter::ConvertGlobalVarIR(global_var_ir);
   1411   return true;
   1412 }
   1413 
   1414 bool ProtobufIRDiffDumper::AddRecordTypeDiffIR(
   1415     const RecordTypeDiffIR *record_diff_ir,
   1416     const std::string &type_stack,
   1417     DiffKind diff_kind) {
   1418   abi_diff::RecordTypeDiff *added_record_type_diff = nullptr;
   1419   switch (diff_kind) {
   1420     case DiffKind::Unreferenced:
   1421       added_record_type_diff = diff_tu_->add_unreferenced_record_type_diffs();
   1422       break;
   1423     case DiffKind::Referenced:
   1424       added_record_type_diff = diff_tu_->add_record_type_diffs();
   1425       break;
   1426     default:
   1427       break;
   1428   }
   1429   if (!added_record_type_diff) {
   1430     return false;
   1431   }
   1432 
   1433   *added_record_type_diff =
   1434       IRDiffToProtobufConverter::ConvertRecordTypeDiffIR(record_diff_ir);
   1435   added_record_type_diff->set_type_stack(type_stack);
   1436   return true;
   1437 }
   1438 
   1439 bool ProtobufIRDiffDumper::AddFunctionDiffIR(
   1440     const FunctionDiffIR *function_diff_ir, const std::string &type_stack,
   1441     DiffKind diff_kind) {
   1442   abi_diff::FunctionDeclDiff *added_function_diff =
   1443       diff_tu_->add_function_diffs();
   1444   if (!added_function_diff) {
   1445     return false;
   1446   }
   1447   *added_function_diff =
   1448       IRDiffToProtobufConverter::ConvertFunctionDiffIR(function_diff_ir);
   1449   return true;
   1450 }
   1451 
   1452 bool ProtobufIRDiffDumper::AddEnumTypeDiffIR(const EnumTypeDiffIR *enum_diff_ir,
   1453                                              const std::string &type_stack,
   1454                                              DiffKind diff_kind) {
   1455   abi_diff::EnumTypeDiff *added_enum_type_diff = nullptr;
   1456   switch (diff_kind) {
   1457     case DiffKind::Unreferenced:
   1458       if (enum_diff_ir->IsExtended()) {
   1459         added_enum_type_diff =
   1460             diff_tu_->add_unreferenced_enum_type_extension_diffs();
   1461       } else {
   1462         added_enum_type_diff =
   1463             diff_tu_->add_unreferenced_enum_type_diffs();
   1464       }
   1465       break;
   1466     case DiffKind::Referenced:
   1467       if (enum_diff_ir->IsExtended()) {
   1468         added_enum_type_diff =
   1469             diff_tu_->add_enum_type_extension_diffs();
   1470       } else {
   1471         added_enum_type_diff =
   1472             diff_tu_->add_enum_type_diffs();
   1473       }
   1474       break;
   1475     default:
   1476       break;
   1477   }
   1478   if (!added_enum_type_diff) {
   1479     return false;
   1480   }
   1481   *added_enum_type_diff =
   1482       IRDiffToProtobufConverter::ConvertEnumTypeDiffIR(enum_diff_ir);
   1483   added_enum_type_diff->set_type_stack(type_stack);
   1484   return true;
   1485 }
   1486 
   1487 bool ProtobufIRDiffDumper::AddGlobalVarDiffIR(
   1488     const GlobalVarDiffIR *global_var_diff_ir,
   1489     const std::string &type_stack,
   1490     DiffKind diff_kind) {
   1491   abi_diff::GlobalVarDeclDiff *added_global_var_diff =
   1492       diff_tu_->add_global_var_diffs();
   1493   if (!added_global_var_diff) {
   1494     return false;
   1495   }
   1496   *added_global_var_diff =
   1497       IRDiffToProtobufConverter::ConvertGlobalVarDiffIR(global_var_diff_ir);
   1498   return true;
   1499 }
   1500 
   1501 bool ProtobufIRDiffDumper::Dump() {
   1502   GOOGLE_PROTOBUF_VERIFY_VERSION;
   1503   assert(diff_tu_.get() != nullptr);
   1504   std::ofstream text_output(dump_path_);
   1505   google::protobuf::io::OstreamOutputStream text_os(&text_output);
   1506   return google::protobuf::TextFormat::Print(*diff_tu_.get(), &text_os);
   1507 }
   1508 
   1509 } //abi_util
   1510