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