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
AddTagTypeInfo(abi_dump::TagType * tag_type_protobuf,const TagTypeIR * tag_type_ir)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
ConvertRecordTypeIR(const RecordTypeIR * recordp)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
ConvertElfObjectIR(const ElfObjectIR * elf_object_ir)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
ConvertElfFunctionIR(const ElfFunctionIR * elf_function_ir)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>
AddFunctionParametersAndSetReturnType(CFunctionLikeMessage * function_like_protobuf,const CFunctionLikeIR * cfunction_like_ir)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>
AddFunctionParameters(CFunctionLikeMessage * function_like_protobuf,const CFunctionLikeIR * cfunction_like_ir)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
ConvertFunctionTypeIR(const FunctionTypeIR * function_typep)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
ConvertFunctionIR(const FunctionIR * functionp)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
AddEnumFields(abi_dump::EnumType * enum_protobuf,const EnumTypeIR * enum_ir)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
ConvertEnumTypeIR(const EnumTypeIR * enump)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
ConvertGlobalVarIR(const GlobalVarIR * global_varp)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
ConvertPointerTypeIR(const PointerTypeIR * pointerp)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
ConvertQualifiedTypeIR(const QualifiedTypeIR * qualtypep)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
ConvertBuiltinTypeIR(const BuiltinTypeIR * builtin_typep)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
ConvertArrayTypeIR(const ArrayTypeIR * array_typep)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
ConvertLvalueReferenceTypeIR(const LvalueReferenceTypeIR * lvalue_reference_typep)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
ConvertRvalueReferenceTypeIR(const RvalueReferenceTypeIR * rvalue_reference_typep)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
AddLinkableMessageIR(const LinkableMessageIR * lm)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
AddElfFunctionIR(const ElfFunctionIR * elf_function)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
AddElfObjectIR(const ElfObjectIR * elf_object)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
AddElfSymbolMessageIR(const ElfSymbolIR * em)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
AddRecordTypeIR(const RecordTypeIR * recordp)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
AddFunctionTypeIR(const FunctionTypeIR * function_typep)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
AddFunctionIR(const FunctionIR * functionp)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
AddEnumTypeIR(const EnumTypeIR * enump)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
AddGlobalVarIR(const GlobalVarIR * global_varp)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
AddPointerTypeIR(const PointerTypeIR * pointerp)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
AddQualifiedTypeIR(const QualifiedTypeIR * qualtypep)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
AddBuiltinTypeIR(const BuiltinTypeIR * builtin_typep)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
AddArrayTypeIR(const ArrayTypeIR * array_typep)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
AddLvalueReferenceTypeIR(const LvalueReferenceTypeIR * lvalue_reference_typep)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
AddRvalueReferenceTypeIR(const RvalueReferenceTypeIR * rvalue_reference_typep)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
Dump(const ModuleIR & module)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
CreateProtobufIRDumper(const std::string & dump_path)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