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 &¶meter : 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