Home | History | Annotate | Download | only in protobuf
      1 // Copyright (C) 2019 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 "repr/protobuf/ir_dumper.h"
     16 
     17 #include "repr/protobuf/abi_dump.h"
     18 #include "repr/protobuf/api.h"
     19 
     20 #include <fstream>
     21 #include <memory>
     22 
     23 #include <llvm/Support/raw_ostream.h>
     24 
     25 #include <google/protobuf/io/zero_copy_stream_impl.h>
     26 #include <google/protobuf/text_format.h>
     27 
     28 
     29 namespace header_checker {
     30 namespace repr {
     31 
     32 
     33 bool IRToProtobufConverter::AddTemplateInformation(
     34     abi_dump::TemplateInfo *ti, const TemplatedArtifactIR *ta) {
     35   for (auto &&template_element : ta->GetTemplateElements()) {
     36     abi_dump::TemplateElement *added_element = ti->add_elements();
     37     if (!added_element) {
     38       llvm::errs() << "Failed to add template element\n";
     39       return false;
     40     }
     41     added_element->set_referenced_type(template_element.GetReferencedType());
     42   }
     43   return true;
     44 }
     45 
     46 bool IRToProtobufConverter::AddTypeInfo(
     47     abi_dump::BasicNamedAndTypedDecl *type_info, const TypeIR *typep) {
     48   if (!type_info || !typep) {
     49     llvm::errs() << "Typeinfo not valid\n";
     50     return false;
     51   }
     52   type_info->set_linker_set_key(typep->GetLinkerSetKey());
     53   type_info->set_source_file(typep->GetSourceFile());
     54   type_info->set_name(typep->GetName());
     55   type_info->set_size(typep->GetSize());
     56   type_info->set_alignment(typep->GetAlignment());
     57   type_info->set_referenced_type(typep->GetReferencedType());
     58   type_info->set_self_type(typep->GetSelfType());
     59   return true;
     60 }
     61 
     62 bool IRToProtobufConverter::AddRecordFields(
     63     abi_dump::RecordType *record_protobuf,
     64     const RecordTypeIR *record_ir) {
     65   // Iterate through the fields and create corresponding ones for the protobuf
     66   // record
     67   for (auto &&field_ir : record_ir->GetFields()) {
     68     abi_dump::RecordFieldDecl *added_field = record_protobuf->add_fields();
     69     if (!added_field) {
     70       llvm::errs() << "Couldn't add record field\n";
     71     }
     72     SetIRToProtobufRecordField(added_field, &field_ir);
     73   }
     74   return true;
     75 }
     76 
     77 bool IRToProtobufConverter::AddBaseSpecifiers(
     78     abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir) {
     79   for (auto &&base_ir : record_ir->GetBases()) {
     80     abi_dump::CXXBaseSpecifier *added_base =
     81         record_protobuf->add_base_specifiers();
     82     if (!SetIRToProtobufBaseSpecifier(added_base, base_ir)) {
     83       return false;
     84     }
     85   }
     86   return true;
     87 }
     88 
     89 bool IRToProtobufConverter::AddVTableLayout(
     90     abi_dump::RecordType *record_protobuf,
     91     const RecordTypeIR *record_ir) {
     92   // If there are no entries in the vtable, just return.
     93   if (record_ir->GetVTableNumEntries() == 0) {
     94     return true;
     95   }
     96   const VTableLayoutIR &vtable_layout_ir = record_ir->GetVTableLayout();
     97   abi_dump::VTableLayout *vtable_layout_protobuf =
     98       record_protobuf->mutable_vtable_layout();
     99   if (!SetIRToProtobufVTableLayout(vtable_layout_protobuf, vtable_layout_ir)) {
    100     return false;
    101   }
    102   return true;
    103 }
    104 
    105 bool IRToProtobufConverter::AddTagTypeInfo(
    106     abi_dump::TagType *tag_type_protobuf,
    107     const TagTypeIR *tag_type_ir) {
    108   if (!tag_type_protobuf || !tag_type_ir) {
    109     return false;
    110   }
    111   tag_type_protobuf->set_unique_id(tag_type_ir->GetUniqueId());
    112   return true;
    113 }
    114 
    115 abi_dump::RecordType IRToProtobufConverter::ConvertRecordTypeIR(
    116     const RecordTypeIR *recordp) {
    117   abi_dump::RecordType added_record_type;
    118   added_record_type.set_access(AccessIRToProtobuf(recordp->GetAccess()));
    119   added_record_type.set_record_kind(
    120       RecordKindIRToProtobuf(recordp->GetRecordKind()));
    121   if (recordp->IsAnonymous()) {
    122     added_record_type.set_is_anonymous(true);
    123   }
    124   if (!AddTypeInfo(added_record_type.mutable_type_info(), recordp) ||
    125       !AddRecordFields(&added_record_type, recordp) ||
    126       !AddBaseSpecifiers(&added_record_type, recordp) ||
    127       !AddVTableLayout(&added_record_type, recordp) ||
    128       !AddTagTypeInfo(added_record_type.mutable_tag_info(), recordp) ||
    129       !(recordp->GetTemplateElements().size() ?
    130         AddTemplateInformation(added_record_type.mutable_template_info(),
    131                                recordp) : true)) {
    132     llvm::errs() << "Template information could not be added\n";
    133     ::exit(1);
    134   }
    135   return added_record_type;
    136 }
    137 
    138 
    139 abi_dump::ElfObject IRToProtobufConverter::ConvertElfObjectIR(
    140     const ElfObjectIR *elf_object_ir) {
    141   abi_dump::ElfObject elf_object_protobuf;
    142   elf_object_protobuf.set_name(elf_object_ir->GetName());
    143   return elf_object_protobuf;
    144 }
    145 
    146 abi_dump::ElfFunction IRToProtobufConverter::ConvertElfFunctionIR(
    147     const ElfFunctionIR *elf_function_ir) {
    148   abi_dump::ElfFunction elf_function_protobuf;
    149   elf_function_protobuf.set_name(elf_function_ir->GetName());
    150   return elf_function_protobuf;
    151 }
    152 
    153 template <typename CFunctionLikeMessage>
    154 bool IRToProtobufConverter::AddFunctionParametersAndSetReturnType(
    155     CFunctionLikeMessage *function_like_protobuf,
    156     const CFunctionLikeIR *cfunction_like_ir) {
    157   function_like_protobuf->set_return_type(cfunction_like_ir->GetReturnType());
    158   return AddFunctionParameters(function_like_protobuf, cfunction_like_ir);
    159 }
    160 
    161 template <typename CFunctionLikeMessage>
    162 bool IRToProtobufConverter::AddFunctionParameters(
    163     CFunctionLikeMessage *function_like_protobuf,
    164     const CFunctionLikeIR *cfunction_like_ir) {
    165   for (auto &&parameter : cfunction_like_ir->GetParameters()) {
    166     abi_dump::ParamDecl *added_parameter =
    167         function_like_protobuf->add_parameters();
    168     if (!added_parameter) {
    169       return false;
    170     }
    171     added_parameter->set_referenced_type(
    172         parameter.GetReferencedType());
    173     added_parameter->set_default_arg(parameter.GetIsDefault());
    174     added_parameter->set_is_this_ptr(parameter.GetIsThisPtr());
    175   }
    176   return true;
    177 }
    178 
    179 abi_dump::FunctionType IRToProtobufConverter::ConvertFunctionTypeIR (
    180     const FunctionTypeIR *function_typep) {
    181   abi_dump::FunctionType added_function_type;
    182   if (!AddTypeInfo(added_function_type.mutable_type_info(), function_typep) ||
    183       !AddFunctionParametersAndSetReturnType(&added_function_type,
    184                                              function_typep)) {
    185     llvm::errs() << "Could not convert FunctionTypeIR to protobuf\n";
    186     ::exit(1);
    187   }
    188   return added_function_type;
    189 }
    190 
    191 abi_dump::FunctionDecl IRToProtobufConverter::ConvertFunctionIR(
    192     const FunctionIR *functionp) {
    193   abi_dump::FunctionDecl added_function;
    194   added_function.set_access(AccessIRToProtobuf(functionp->GetAccess()));
    195   added_function.set_linker_set_key(functionp->GetLinkerSetKey());
    196   added_function.set_source_file(functionp->GetSourceFile());
    197   added_function.set_function_name(functionp->GetName());
    198   if (!AddFunctionParametersAndSetReturnType(&added_function, functionp) ||
    199       !(functionp->GetTemplateElements().size() ?
    200       AddTemplateInformation(added_function.mutable_template_info(), functionp)
    201       : true)) {
    202     llvm::errs() << "Template information could not be added\n";
    203     ::exit(1);
    204   }
    205   return added_function;
    206 }
    207 
    208 bool IRToProtobufConverter::AddEnumFields(abi_dump::EnumType *enum_protobuf,
    209                                           const EnumTypeIR *enum_ir) {
    210   for (auto &&field : enum_ir->GetFields()) {
    211     abi_dump::EnumFieldDecl *enum_fieldp = enum_protobuf->add_enum_fields();
    212     if (!SetIRToProtobufEnumField(enum_fieldp, &field)) {
    213       return false;
    214     }
    215   }
    216   return true;
    217 }
    218 
    219 
    220 abi_dump::EnumType IRToProtobufConverter::ConvertEnumTypeIR(
    221     const EnumTypeIR *enump) {
    222   abi_dump::EnumType added_enum_type;
    223   added_enum_type.set_access(AccessIRToProtobuf(enump->GetAccess()));
    224   added_enum_type.set_underlying_type(enump->GetUnderlyingType());
    225   if (!AddTypeInfo(added_enum_type.mutable_type_info(), enump) ||
    226       !AddEnumFields(&added_enum_type, enump) ||
    227       !AddTagTypeInfo(added_enum_type.mutable_tag_info(), enump)) {
    228     llvm::errs() << "EnumTypeIR could not be converted\n";
    229     ::exit(1);
    230   }
    231   return added_enum_type;
    232 }
    233 
    234 abi_dump::GlobalVarDecl IRToProtobufConverter::ConvertGlobalVarIR(
    235     const GlobalVarIR *global_varp) {
    236   abi_dump::GlobalVarDecl added_global_var;
    237   added_global_var.set_referenced_type(global_varp->GetReferencedType());
    238   added_global_var.set_source_file(global_varp->GetSourceFile());
    239   added_global_var.set_name(global_varp->GetName());
    240   added_global_var.set_linker_set_key(global_varp->GetLinkerSetKey());
    241   added_global_var.set_access(
    242       AccessIRToProtobuf(global_varp->GetAccess()));
    243   return added_global_var;
    244 }
    245 
    246 abi_dump::PointerType IRToProtobufConverter::ConvertPointerTypeIR(
    247     const PointerTypeIR *pointerp) {
    248   abi_dump::PointerType added_pointer_type;
    249   if (!AddTypeInfo(added_pointer_type.mutable_type_info(), pointerp)) {
    250     llvm::errs() << "PointerTypeIR could not be converted\n";
    251     ::exit(1);
    252   }
    253   return added_pointer_type;
    254 }
    255 
    256 abi_dump::QualifiedType IRToProtobufConverter::ConvertQualifiedTypeIR(
    257     const QualifiedTypeIR *qualtypep) {
    258   abi_dump::QualifiedType added_qualified_type;
    259   if (!AddTypeInfo(added_qualified_type.mutable_type_info(), qualtypep)) {
    260     llvm::errs() << "QualifiedTypeIR could not be converted\n";
    261     ::exit(1);
    262   }
    263   added_qualified_type.set_is_const(qualtypep->IsConst());
    264   added_qualified_type.set_is_volatile(qualtypep->IsVolatile());
    265   added_qualified_type.set_is_restricted(qualtypep->IsRestricted());
    266   return added_qualified_type;
    267 }
    268 
    269 abi_dump::BuiltinType IRToProtobufConverter::ConvertBuiltinTypeIR(
    270     const BuiltinTypeIR *builtin_typep) {
    271   abi_dump::BuiltinType added_builtin_type;
    272   added_builtin_type.set_is_unsigned(builtin_typep->IsUnsigned());
    273   added_builtin_type.set_is_integral(builtin_typep->IsIntegralType());
    274   if (!AddTypeInfo(added_builtin_type.mutable_type_info(), builtin_typep)) {
    275     llvm::errs() << "BuiltinTypeIR could not be converted\n";
    276     ::exit(1);
    277   }
    278   return added_builtin_type;
    279 }
    280 
    281 abi_dump::ArrayType IRToProtobufConverter::ConvertArrayTypeIR(
    282     const ArrayTypeIR *array_typep) {
    283   abi_dump::ArrayType added_array_type;
    284   if (!AddTypeInfo(added_array_type.mutable_type_info(), array_typep)) {
    285     llvm::errs() << "ArrayTypeIR could not be converted\n";
    286     ::exit(1);
    287   }
    288   return added_array_type;
    289 }
    290 
    291 abi_dump::LvalueReferenceType
    292 IRToProtobufConverter::ConvertLvalueReferenceTypeIR(
    293     const LvalueReferenceTypeIR *lvalue_reference_typep) {
    294   abi_dump::LvalueReferenceType added_lvalue_reference_type;
    295   if (!AddTypeInfo(added_lvalue_reference_type.mutable_type_info(),
    296                    lvalue_reference_typep)) {
    297     llvm::errs() << "LvalueReferenceTypeIR could not be converted\n";
    298     ::exit(1);
    299   }
    300   return added_lvalue_reference_type;
    301 }
    302 
    303 abi_dump::RvalueReferenceType
    304 IRToProtobufConverter::ConvertRvalueReferenceTypeIR(
    305     const RvalueReferenceTypeIR *rvalue_reference_typep) {
    306   abi_dump::RvalueReferenceType added_rvalue_reference_type;
    307   if (!AddTypeInfo(added_rvalue_reference_type.mutable_type_info(),
    308                    rvalue_reference_typep)) {
    309     llvm::errs() << "RvalueReferenceTypeIR could not be converted\n";
    310     ::exit(1);
    311   }
    312   return added_rvalue_reference_type;
    313 }
    314 
    315 bool ProtobufIRDumper::AddLinkableMessageIR (const LinkableMessageIR *lm) {
    316   // No RTTI
    317   switch (lm->GetKind()) {
    318     case RecordTypeKind:
    319       return AddRecordTypeIR(static_cast<const RecordTypeIR *>(lm));
    320     case EnumTypeKind:
    321       return AddEnumTypeIR(static_cast<const EnumTypeIR *>(lm));
    322     case PointerTypeKind:
    323       return AddPointerTypeIR(static_cast<const PointerTypeIR *>(lm));
    324     case QualifiedTypeKind:
    325       return AddQualifiedTypeIR(static_cast<const QualifiedTypeIR *>(lm));
    326     case ArrayTypeKind:
    327       return AddArrayTypeIR(static_cast<const ArrayTypeIR *>(lm));
    328     case LvalueReferenceTypeKind:
    329       return AddLvalueReferenceTypeIR(
    330           static_cast<const LvalueReferenceTypeIR *>(lm));
    331     case RvalueReferenceTypeKind:
    332       return AddRvalueReferenceTypeIR(
    333           static_cast<const RvalueReferenceTypeIR*>(lm));
    334     case BuiltinTypeKind:
    335       return AddBuiltinTypeIR(static_cast<const BuiltinTypeIR*>(lm));
    336     case FunctionTypeKind:
    337       return AddFunctionTypeIR(static_cast<const FunctionTypeIR*>(lm));
    338     case GlobalVarKind:
    339       return AddGlobalVarIR(static_cast<const GlobalVarIR*>(lm));
    340     case FunctionKind:
    341       return AddFunctionIR(static_cast<const FunctionIR*>(lm));
    342   }
    343   return false;
    344 }
    345 
    346 bool ProtobufIRDumper::AddElfFunctionIR(const ElfFunctionIR *elf_function) {
    347   abi_dump::ElfFunction *added_elf_function = tu_ptr_->add_elf_functions();
    348   if (!added_elf_function) {
    349     return false;
    350   }
    351   added_elf_function->set_name(elf_function->GetName());
    352   added_elf_function->set_binding(
    353       ElfSymbolBindingIRToProtobuf(elf_function->GetBinding()));
    354   return true;
    355 }
    356 
    357 bool ProtobufIRDumper::AddElfObjectIR(const ElfObjectIR *elf_object) {
    358   abi_dump::ElfObject *added_elf_object = tu_ptr_->add_elf_objects();
    359   if (!added_elf_object) {
    360     return false;
    361   }
    362   added_elf_object->set_name(elf_object->GetName());
    363   added_elf_object->set_binding(
    364       ElfSymbolBindingIRToProtobuf(elf_object->GetBinding()));
    365   return true;
    366 }
    367 
    368 bool ProtobufIRDumper::AddElfSymbolMessageIR(const ElfSymbolIR *em) {
    369   switch (em->GetKind()) {
    370     case ElfSymbolIR::ElfFunctionKind:
    371       return AddElfFunctionIR(static_cast<const ElfFunctionIR *>(em));
    372     case ElfSymbolIR::ElfObjectKind:
    373       return AddElfObjectIR(static_cast<const ElfObjectIR *>(em));
    374   }
    375   return false;
    376 }
    377 
    378 bool ProtobufIRDumper::AddRecordTypeIR(const RecordTypeIR *recordp) {
    379   abi_dump::RecordType *added_record_type = tu_ptr_->add_record_types();
    380   if (!added_record_type) {
    381     return false;
    382   }
    383   *added_record_type = ConvertRecordTypeIR(recordp);
    384   return true;
    385 }
    386 
    387 bool ProtobufIRDumper::AddFunctionTypeIR(const FunctionTypeIR *function_typep) {
    388   abi_dump::FunctionType *added_function_type = tu_ptr_->add_function_types();
    389   if (!added_function_type) {
    390     return false;
    391   }
    392   *added_function_type = ConvertFunctionTypeIR(function_typep);
    393   return true;
    394 }
    395 
    396 bool ProtobufIRDumper::AddFunctionIR(const FunctionIR *functionp) {
    397   abi_dump::FunctionDecl *added_function = tu_ptr_->add_functions();
    398   if (!added_function) {
    399     return false;
    400   }
    401   *added_function = ConvertFunctionIR(functionp);
    402   return true;
    403 }
    404 
    405 bool ProtobufIRDumper::AddEnumTypeIR(const EnumTypeIR *enump) {
    406   abi_dump::EnumType *added_enum_type = tu_ptr_->add_enum_types();
    407   if (!added_enum_type) {
    408     return false;
    409   }
    410   *added_enum_type = ConvertEnumTypeIR(enump);
    411   return true;
    412 }
    413 
    414 bool ProtobufIRDumper::AddGlobalVarIR(const GlobalVarIR *global_varp) {
    415   abi_dump::GlobalVarDecl *added_global_var = tu_ptr_->add_global_vars();
    416   if (!added_global_var) {
    417     return false;
    418   }
    419   *added_global_var = ConvertGlobalVarIR(global_varp);
    420   return true;
    421 }
    422 
    423 bool ProtobufIRDumper::AddPointerTypeIR(const PointerTypeIR *pointerp) {
    424   abi_dump::PointerType *added_pointer_type = tu_ptr_->add_pointer_types();
    425   if (!added_pointer_type) {
    426     return false;
    427   }
    428   *added_pointer_type = ConvertPointerTypeIR(pointerp);
    429   return true;
    430 }
    431 
    432 bool ProtobufIRDumper::AddQualifiedTypeIR(const QualifiedTypeIR *qualtypep) {
    433   abi_dump::QualifiedType *added_qualified_type =
    434       tu_ptr_->add_qualified_types();
    435   if (!added_qualified_type) {
    436     return false;
    437   }
    438   *added_qualified_type = ConvertQualifiedTypeIR(qualtypep);
    439   return true;
    440 }
    441 
    442 bool ProtobufIRDumper::AddBuiltinTypeIR(const BuiltinTypeIR *builtin_typep) {
    443   abi_dump::BuiltinType *added_builtin_type =
    444       tu_ptr_->add_builtin_types();
    445   if (!added_builtin_type) {
    446     return false;
    447   }
    448   *added_builtin_type = ConvertBuiltinTypeIR(builtin_typep);
    449   return true;
    450 }
    451 
    452 bool ProtobufIRDumper::AddArrayTypeIR(const ArrayTypeIR *array_typep) {
    453   abi_dump::ArrayType *added_array_type =
    454       tu_ptr_->add_array_types();
    455   if (!added_array_type) {
    456     return false;
    457   }
    458   *added_array_type = ConvertArrayTypeIR(array_typep);
    459   return true;
    460 }
    461 
    462 bool ProtobufIRDumper::AddLvalueReferenceTypeIR(
    463     const LvalueReferenceTypeIR *lvalue_reference_typep) {
    464   abi_dump::LvalueReferenceType *added_lvalue_reference_type =
    465       tu_ptr_->add_lvalue_reference_types();
    466   if (!added_lvalue_reference_type) {
    467     return false;
    468   }
    469   *added_lvalue_reference_type =
    470       ConvertLvalueReferenceTypeIR(lvalue_reference_typep);
    471   return true;
    472 }
    473 
    474 bool ProtobufIRDumper::AddRvalueReferenceTypeIR(
    475     const RvalueReferenceTypeIR *rvalue_reference_typep) {
    476   abi_dump::RvalueReferenceType *added_rvalue_reference_type =
    477       tu_ptr_->add_rvalue_reference_types();
    478   if (!added_rvalue_reference_type) {
    479     return false;
    480   }
    481   *added_rvalue_reference_type =
    482       ConvertRvalueReferenceTypeIR(rvalue_reference_typep);
    483   return true;
    484 }
    485 
    486 bool ProtobufIRDumper::Dump(const ModuleIR &module) {
    487   GOOGLE_PROTOBUF_VERIFY_VERSION;
    488   DumpModule(module);
    489   assert( tu_ptr_.get() != nullptr);
    490   std::ofstream text_output(dump_path_);
    491   google::protobuf::io::OstreamOutputStream text_os(&text_output);
    492   return google::protobuf::TextFormat::Print(*tu_ptr_.get(), &text_os);
    493 }
    494 
    495 std::unique_ptr<IRDumper> CreateProtobufIRDumper(const std::string &dump_path) {
    496   return std::make_unique<ProtobufIRDumper>(dump_path);
    497 }
    498 
    499 
    500 }  // namespace repr
    501 }  // namespace header_checker
    502