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 
AddTemplateInformation(abi_dump::TemplateInfo * ti,const TemplatedArtifactIR * ta)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 
AddTypeInfo(abi_dump::BasicNamedAndTypedDecl * type_info,const TypeIR * typep)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 
AddRecordFields(abi_dump::RecordType * record_protobuf,const RecordTypeIR * record_ir)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 
AddBaseSpecifiers(abi_dump::RecordType * record_protobuf,const RecordTypeIR * record_ir)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 
AddVTableLayout(abi_dump::RecordType * record_protobuf,const RecordTypeIR * record_ir)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 
ConvertRecordTypeIR(const RecordTypeIR * recordp)105 abi_dump::RecordType IRToProtobufConverter::ConvertRecordTypeIR(
106     const RecordTypeIR *recordp) {
107   abi_dump::RecordType added_record_type;
108   added_record_type.set_access(AccessIRToProtobuf(recordp->GetAccess()));
109   added_record_type.set_record_kind(
110       RecordKindIRToProtobuf(recordp->GetRecordKind()));
111   if (recordp->IsAnonymous()) {
112     added_record_type.set_is_anonymous(true);
113   }
114   if (!AddTypeInfo(added_record_type.mutable_type_info(), recordp) ||
115       !AddRecordFields(&added_record_type, recordp) ||
116       !AddBaseSpecifiers(&added_record_type, recordp) ||
117       !AddVTableLayout(&added_record_type, recordp) ||
118       !(recordp->GetTemplateElements().size() ?
119         AddTemplateInformation(added_record_type.mutable_template_info(),
120                                recordp) : true)) {
121     llvm::errs() << "Template information could not be added\n";
122     ::exit(1);
123   }
124   return added_record_type;
125 }
126 
127 
ConvertElfObjectIR(const ElfObjectIR * elf_object_ir)128 abi_dump::ElfObject IRToProtobufConverter::ConvertElfObjectIR(
129     const ElfObjectIR *elf_object_ir) {
130   abi_dump::ElfObject elf_object_protobuf;
131   elf_object_protobuf.set_name(elf_object_ir->GetName());
132   return elf_object_protobuf;
133 }
134 
ConvertElfFunctionIR(const ElfFunctionIR * elf_function_ir)135 abi_dump::ElfFunction IRToProtobufConverter::ConvertElfFunctionIR(
136     const ElfFunctionIR *elf_function_ir) {
137   abi_dump::ElfFunction elf_function_protobuf;
138   elf_function_protobuf.set_name(elf_function_ir->GetName());
139   return elf_function_protobuf;
140 }
141 
142 template <typename CFunctionLikeMessage>
AddFunctionParametersAndSetReturnType(CFunctionLikeMessage * function_like_protobuf,const CFunctionLikeIR * cfunction_like_ir)143 bool IRToProtobufConverter::AddFunctionParametersAndSetReturnType(
144     CFunctionLikeMessage *function_like_protobuf,
145     const CFunctionLikeIR *cfunction_like_ir) {
146   function_like_protobuf->set_return_type(cfunction_like_ir->GetReturnType());
147   return AddFunctionParameters(function_like_protobuf, cfunction_like_ir);
148 }
149 
150 template <typename CFunctionLikeMessage>
AddFunctionParameters(CFunctionLikeMessage * function_like_protobuf,const CFunctionLikeIR * cfunction_like_ir)151 bool IRToProtobufConverter::AddFunctionParameters(
152     CFunctionLikeMessage *function_like_protobuf,
153     const CFunctionLikeIR *cfunction_like_ir) {
154   for (auto &&parameter : cfunction_like_ir->GetParameters()) {
155     abi_dump::ParamDecl *added_parameter =
156         function_like_protobuf->add_parameters();
157     if (!added_parameter) {
158       return false;
159     }
160     added_parameter->set_referenced_type(
161         parameter.GetReferencedType());
162     added_parameter->set_default_arg(parameter.GetIsDefault());
163     added_parameter->set_is_this_ptr(parameter.GetIsThisPtr());
164   }
165   return true;
166 }
167 
ConvertFunctionTypeIR(const FunctionTypeIR * function_typep)168 abi_dump::FunctionType IRToProtobufConverter::ConvertFunctionTypeIR (
169     const FunctionTypeIR *function_typep) {
170   abi_dump::FunctionType added_function_type;
171   if (!AddTypeInfo(added_function_type.mutable_type_info(), function_typep) ||
172       !AddFunctionParametersAndSetReturnType(&added_function_type,
173                                              function_typep)) {
174     llvm::errs() << "Could not convert FunctionTypeIR to protobuf\n";
175     ::exit(1);
176   }
177   return added_function_type;
178 }
179 
ConvertFunctionIR(const FunctionIR * functionp)180 abi_dump::FunctionDecl IRToProtobufConverter::ConvertFunctionIR(
181     const FunctionIR *functionp) {
182   abi_dump::FunctionDecl added_function;
183   added_function.set_access(AccessIRToProtobuf(functionp->GetAccess()));
184   added_function.set_linker_set_key(functionp->GetLinkerSetKey());
185   added_function.set_source_file(functionp->GetSourceFile());
186   added_function.set_function_name(functionp->GetName());
187   if (!AddFunctionParametersAndSetReturnType(&added_function, functionp) ||
188       !(functionp->GetTemplateElements().size() ?
189       AddTemplateInformation(added_function.mutable_template_info(), functionp)
190       : true)) {
191     llvm::errs() << "Template information could not be added\n";
192     ::exit(1);
193   }
194   return added_function;
195 }
196 
AddEnumFields(abi_dump::EnumType * enum_protobuf,const EnumTypeIR * enum_ir)197 bool IRToProtobufConverter::AddEnumFields(abi_dump::EnumType *enum_protobuf,
198                                           const EnumTypeIR *enum_ir) {
199   for (auto &&field : enum_ir->GetFields()) {
200     abi_dump::EnumFieldDecl *enum_fieldp = enum_protobuf->add_enum_fields();
201     if (!SetIRToProtobufEnumField(enum_fieldp, &field)) {
202       return false;
203     }
204   }
205   return true;
206 }
207 
208 
ConvertEnumTypeIR(const EnumTypeIR * enump)209 abi_dump::EnumType IRToProtobufConverter::ConvertEnumTypeIR(
210     const EnumTypeIR *enump) {
211   abi_dump::EnumType added_enum_type;
212   added_enum_type.set_access(AccessIRToProtobuf(enump->GetAccess()));
213   added_enum_type.set_underlying_type(enump->GetUnderlyingType());
214   if (!AddTypeInfo(added_enum_type.mutable_type_info(), enump) ||
215       !AddEnumFields(&added_enum_type, enump)) {
216     llvm::errs() << "EnumTypeIR could not be converted\n";
217     ::exit(1);
218   }
219   return added_enum_type;
220 }
221 
ConvertGlobalVarIR(const GlobalVarIR * global_varp)222 abi_dump::GlobalVarDecl IRToProtobufConverter::ConvertGlobalVarIR(
223     const GlobalVarIR *global_varp) {
224   abi_dump::GlobalVarDecl added_global_var;
225   added_global_var.set_referenced_type(global_varp->GetReferencedType());
226   added_global_var.set_source_file(global_varp->GetSourceFile());
227   added_global_var.set_name(global_varp->GetName());
228   added_global_var.set_linker_set_key(global_varp->GetLinkerSetKey());
229   added_global_var.set_access(
230       AccessIRToProtobuf(global_varp->GetAccess()));
231   return added_global_var;
232 }
233 
ConvertPointerTypeIR(const PointerTypeIR * pointerp)234 abi_dump::PointerType IRToProtobufConverter::ConvertPointerTypeIR(
235     const PointerTypeIR *pointerp) {
236   abi_dump::PointerType added_pointer_type;
237   if (!AddTypeInfo(added_pointer_type.mutable_type_info(), pointerp)) {
238     llvm::errs() << "PointerTypeIR could not be converted\n";
239     ::exit(1);
240   }
241   return added_pointer_type;
242 }
243 
ConvertQualifiedTypeIR(const QualifiedTypeIR * qualtypep)244 abi_dump::QualifiedType IRToProtobufConverter::ConvertQualifiedTypeIR(
245     const QualifiedTypeIR *qualtypep) {
246   abi_dump::QualifiedType added_qualified_type;
247   if (!AddTypeInfo(added_qualified_type.mutable_type_info(), qualtypep)) {
248     llvm::errs() << "QualifiedTypeIR could not be converted\n";
249     ::exit(1);
250   }
251   added_qualified_type.set_is_const(qualtypep->IsConst());
252   added_qualified_type.set_is_volatile(qualtypep->IsVolatile());
253   added_qualified_type.set_is_restricted(qualtypep->IsRestricted());
254   return added_qualified_type;
255 }
256 
ConvertBuiltinTypeIR(const BuiltinTypeIR * builtin_typep)257 abi_dump::BuiltinType IRToProtobufConverter::ConvertBuiltinTypeIR(
258     const BuiltinTypeIR *builtin_typep) {
259   abi_dump::BuiltinType added_builtin_type;
260   added_builtin_type.set_is_unsigned(builtin_typep->IsUnsigned());
261   added_builtin_type.set_is_integral(builtin_typep->IsIntegralType());
262   if (!AddTypeInfo(added_builtin_type.mutable_type_info(), builtin_typep)) {
263     llvm::errs() << "BuiltinTypeIR could not be converted\n";
264     ::exit(1);
265   }
266   return added_builtin_type;
267 }
268 
ConvertArrayTypeIR(const ArrayTypeIR * array_typep)269 abi_dump::ArrayType IRToProtobufConverter::ConvertArrayTypeIR(
270     const ArrayTypeIR *array_typep) {
271   abi_dump::ArrayType added_array_type;
272   if (!AddTypeInfo(added_array_type.mutable_type_info(), array_typep)) {
273     llvm::errs() << "ArrayTypeIR could not be converted\n";
274     ::exit(1);
275   }
276   return added_array_type;
277 }
278 
279 abi_dump::LvalueReferenceType
ConvertLvalueReferenceTypeIR(const LvalueReferenceTypeIR * lvalue_reference_typep)280 IRToProtobufConverter::ConvertLvalueReferenceTypeIR(
281     const LvalueReferenceTypeIR *lvalue_reference_typep) {
282   abi_dump::LvalueReferenceType added_lvalue_reference_type;
283   if (!AddTypeInfo(added_lvalue_reference_type.mutable_type_info(),
284                    lvalue_reference_typep)) {
285     llvm::errs() << "LvalueReferenceTypeIR could not be converted\n";
286     ::exit(1);
287   }
288   return added_lvalue_reference_type;
289 }
290 
291 abi_dump::RvalueReferenceType
ConvertRvalueReferenceTypeIR(const RvalueReferenceTypeIR * rvalue_reference_typep)292 IRToProtobufConverter::ConvertRvalueReferenceTypeIR(
293     const RvalueReferenceTypeIR *rvalue_reference_typep) {
294   abi_dump::RvalueReferenceType added_rvalue_reference_type;
295   if (!AddTypeInfo(added_rvalue_reference_type.mutable_type_info(),
296                    rvalue_reference_typep)) {
297     llvm::errs() << "RvalueReferenceTypeIR could not be converted\n";
298     ::exit(1);
299   }
300   return added_rvalue_reference_type;
301 }
302 
AddLinkableMessageIR(const LinkableMessageIR * lm)303 bool ProtobufIRDumper::AddLinkableMessageIR (const LinkableMessageIR *lm) {
304   // No RTTI
305   switch (lm->GetKind()) {
306     case RecordTypeKind:
307       return AddRecordTypeIR(static_cast<const RecordTypeIR *>(lm));
308     case EnumTypeKind:
309       return AddEnumTypeIR(static_cast<const EnumTypeIR *>(lm));
310     case PointerTypeKind:
311       return AddPointerTypeIR(static_cast<const PointerTypeIR *>(lm));
312     case QualifiedTypeKind:
313       return AddQualifiedTypeIR(static_cast<const QualifiedTypeIR *>(lm));
314     case ArrayTypeKind:
315       return AddArrayTypeIR(static_cast<const ArrayTypeIR *>(lm));
316     case LvalueReferenceTypeKind:
317       return AddLvalueReferenceTypeIR(
318           static_cast<const LvalueReferenceTypeIR *>(lm));
319     case RvalueReferenceTypeKind:
320       return AddRvalueReferenceTypeIR(
321           static_cast<const RvalueReferenceTypeIR*>(lm));
322     case BuiltinTypeKind:
323       return AddBuiltinTypeIR(static_cast<const BuiltinTypeIR*>(lm));
324     case FunctionTypeKind:
325       return AddFunctionTypeIR(static_cast<const FunctionTypeIR*>(lm));
326     case GlobalVarKind:
327       return AddGlobalVarIR(static_cast<const GlobalVarIR*>(lm));
328     case FunctionKind:
329       return AddFunctionIR(static_cast<const FunctionIR*>(lm));
330   }
331   return false;
332 }
333 
AddElfFunctionIR(const ElfFunctionIR * elf_function)334 bool ProtobufIRDumper::AddElfFunctionIR(const ElfFunctionIR *elf_function) {
335   abi_dump::ElfFunction *added_elf_function = tu_ptr_->add_elf_functions();
336   if (!added_elf_function) {
337     return false;
338   }
339   added_elf_function->set_name(elf_function->GetName());
340   added_elf_function->set_binding(
341       ElfSymbolBindingIRToProtobuf(elf_function->GetBinding()));
342   return true;
343 }
344 
AddElfObjectIR(const ElfObjectIR * elf_object)345 bool ProtobufIRDumper::AddElfObjectIR(const ElfObjectIR *elf_object) {
346   abi_dump::ElfObject *added_elf_object = tu_ptr_->add_elf_objects();
347   if (!added_elf_object) {
348     return false;
349   }
350   added_elf_object->set_name(elf_object->GetName());
351   added_elf_object->set_binding(
352       ElfSymbolBindingIRToProtobuf(elf_object->GetBinding()));
353   return true;
354 }
355 
AddElfSymbolMessageIR(const ElfSymbolIR * em)356 bool ProtobufIRDumper::AddElfSymbolMessageIR(const ElfSymbolIR *em) {
357   switch (em->GetKind()) {
358     case ElfSymbolIR::ElfFunctionKind:
359       return AddElfFunctionIR(static_cast<const ElfFunctionIR *>(em));
360     case ElfSymbolIR::ElfObjectKind:
361       return AddElfObjectIR(static_cast<const ElfObjectIR *>(em));
362   }
363   return false;
364 }
365 
AddRecordTypeIR(const RecordTypeIR * recordp)366 bool ProtobufIRDumper::AddRecordTypeIR(const RecordTypeIR *recordp) {
367   abi_dump::RecordType *added_record_type = tu_ptr_->add_record_types();
368   if (!added_record_type) {
369     return false;
370   }
371   *added_record_type = ConvertRecordTypeIR(recordp);
372   return true;
373 }
374 
AddFunctionTypeIR(const FunctionTypeIR * function_typep)375 bool ProtobufIRDumper::AddFunctionTypeIR(const FunctionTypeIR *function_typep) {
376   abi_dump::FunctionType *added_function_type = tu_ptr_->add_function_types();
377   if (!added_function_type) {
378     return false;
379   }
380   *added_function_type = ConvertFunctionTypeIR(function_typep);
381   return true;
382 }
383 
AddFunctionIR(const FunctionIR * functionp)384 bool ProtobufIRDumper::AddFunctionIR(const FunctionIR *functionp) {
385   abi_dump::FunctionDecl *added_function = tu_ptr_->add_functions();
386   if (!added_function) {
387     return false;
388   }
389   *added_function = ConvertFunctionIR(functionp);
390   return true;
391 }
392 
AddEnumTypeIR(const EnumTypeIR * enump)393 bool ProtobufIRDumper::AddEnumTypeIR(const EnumTypeIR *enump) {
394   abi_dump::EnumType *added_enum_type = tu_ptr_->add_enum_types();
395   if (!added_enum_type) {
396     return false;
397   }
398   *added_enum_type = ConvertEnumTypeIR(enump);
399   return true;
400 }
401 
AddGlobalVarIR(const GlobalVarIR * global_varp)402 bool ProtobufIRDumper::AddGlobalVarIR(const GlobalVarIR *global_varp) {
403   abi_dump::GlobalVarDecl *added_global_var = tu_ptr_->add_global_vars();
404   if (!added_global_var) {
405     return false;
406   }
407   *added_global_var = ConvertGlobalVarIR(global_varp);
408   return true;
409 }
410 
AddPointerTypeIR(const PointerTypeIR * pointerp)411 bool ProtobufIRDumper::AddPointerTypeIR(const PointerTypeIR *pointerp) {
412   abi_dump::PointerType *added_pointer_type = tu_ptr_->add_pointer_types();
413   if (!added_pointer_type) {
414     return false;
415   }
416   *added_pointer_type = ConvertPointerTypeIR(pointerp);
417   return true;
418 }
419 
AddQualifiedTypeIR(const QualifiedTypeIR * qualtypep)420 bool ProtobufIRDumper::AddQualifiedTypeIR(const QualifiedTypeIR *qualtypep) {
421   abi_dump::QualifiedType *added_qualified_type =
422       tu_ptr_->add_qualified_types();
423   if (!added_qualified_type) {
424     return false;
425   }
426   *added_qualified_type = ConvertQualifiedTypeIR(qualtypep);
427   return true;
428 }
429 
AddBuiltinTypeIR(const BuiltinTypeIR * builtin_typep)430 bool ProtobufIRDumper::AddBuiltinTypeIR(const BuiltinTypeIR *builtin_typep) {
431   abi_dump::BuiltinType *added_builtin_type =
432       tu_ptr_->add_builtin_types();
433   if (!added_builtin_type) {
434     return false;
435   }
436   *added_builtin_type = ConvertBuiltinTypeIR(builtin_typep);
437   return true;
438 }
439 
AddArrayTypeIR(const ArrayTypeIR * array_typep)440 bool ProtobufIRDumper::AddArrayTypeIR(const ArrayTypeIR *array_typep) {
441   abi_dump::ArrayType *added_array_type =
442       tu_ptr_->add_array_types();
443   if (!added_array_type) {
444     return false;
445   }
446   *added_array_type = ConvertArrayTypeIR(array_typep);
447   return true;
448 }
449 
AddLvalueReferenceTypeIR(const LvalueReferenceTypeIR * lvalue_reference_typep)450 bool ProtobufIRDumper::AddLvalueReferenceTypeIR(
451     const LvalueReferenceTypeIR *lvalue_reference_typep) {
452   abi_dump::LvalueReferenceType *added_lvalue_reference_type =
453       tu_ptr_->add_lvalue_reference_types();
454   if (!added_lvalue_reference_type) {
455     return false;
456   }
457   *added_lvalue_reference_type =
458       ConvertLvalueReferenceTypeIR(lvalue_reference_typep);
459   return true;
460 }
461 
AddRvalueReferenceTypeIR(const RvalueReferenceTypeIR * rvalue_reference_typep)462 bool ProtobufIRDumper::AddRvalueReferenceTypeIR(
463     const RvalueReferenceTypeIR *rvalue_reference_typep) {
464   abi_dump::RvalueReferenceType *added_rvalue_reference_type =
465       tu_ptr_->add_rvalue_reference_types();
466   if (!added_rvalue_reference_type) {
467     return false;
468   }
469   *added_rvalue_reference_type =
470       ConvertRvalueReferenceTypeIR(rvalue_reference_typep);
471   return true;
472 }
473 
Dump(const ModuleIR & module)474 bool ProtobufIRDumper::Dump(const ModuleIR &module) {
475   GOOGLE_PROTOBUF_VERIFY_VERSION;
476   DumpModule(module);
477   assert( tu_ptr_.get() != nullptr);
478   std::ofstream text_output(dump_path_);
479   google::protobuf::io::OstreamOutputStream text_os(&text_output);
480   return google::protobuf::TextFormat::Print(*tu_ptr_.get(), &text_os);
481 }
482 
CreateProtobufIRDumper(const std::string & dump_path)483 std::unique_ptr<IRDumper> CreateProtobufIRDumper(const std::string &dump_path) {
484   return std::make_unique<ProtobufIRDumper>(dump_path);
485 }
486 
487 
488 }  // namespace repr
489 }  // namespace header_checker
490