1 // Copyright (C) 2017 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 <ir_representation_protobuf.h>
16 
17 #include <llvm/Support/raw_ostream.h>
18 
19 #include <fstream>
20 #include <iostream>
21 #include <string>
22 #include <memory>
23 
24 namespace abi_util {
25 
IsPresentInExportedHeaders(const LinkableMessageIR & linkable_message,const std::set<std::string> * exported_headers)26 static bool IsPresentInExportedHeaders(
27     const LinkableMessageIR &linkable_message,
28     const std::set<std::string> *exported_headers) {
29   if (exported_headers == nullptr || exported_headers->empty()) {
30     return true;
31   }
32   return exported_headers->find(linkable_message.GetSourceFile())
33       != exported_headers->end();
34 }
35 
ReadTypeInfo(const abi_dump::BasicNamedAndTypedDecl & type_info,TypeIR * typep)36 void ProtobufTextFormatToIRReader::ReadTypeInfo(
37     const abi_dump::BasicNamedAndTypedDecl &type_info,
38     TypeIR *typep) {
39   typep->SetLinkerSetKey(type_info.linker_set_key());
40   typep->SetName(type_info.name());
41   typep->SetSourceFile(type_info.source_file());
42   typep->SetReferencedType(type_info.referenced_type());
43   typep->SetSelfType(type_info.self_type());
44   typep->SetSize(type_info.size());
45   typep->SetAlignment(type_info.alignment());
46 }
47 
ReadDump(const std::string & dump_file)48 bool ProtobufTextFormatToIRReader::ReadDump(const std::string &dump_file) {
49   abi_dump::TranslationUnit tu;
50   std::ifstream input(dump_file);
51   google::protobuf::io::IstreamInputStream text_is(&input);
52 
53   if (!google::protobuf::TextFormat::Parse(&text_is, &tu)) {
54     llvm::errs() << "Failed to parse protobuf TextFormat file\n";
55     return false;
56   }
57   ReadFunctions(tu);
58   ReadGlobalVariables(tu);
59 
60   ReadEnumTypes(tu);
61   ReadRecordTypes(tu);
62   ReadFunctionTypes(tu);
63   ReadArrayTypes(tu);
64   ReadPointerTypes(tu);
65   ReadQualifiedTypes(tu);
66   ReadBuiltinTypes(tu);
67   ReadLvalueReferenceTypes(tu);
68   ReadRvalueReferenceTypes(tu);
69 
70   ReadElfFunctions(tu);
71   ReadElfObjects(tu);
72   return true;
73 }
74 
TemplateInfoProtobufToIR(const abi_dump::TemplateInfo & template_info_protobuf)75 TemplateInfoIR ProtobufTextFormatToIRReader::TemplateInfoProtobufToIR(
76     const abi_dump::TemplateInfo &template_info_protobuf) {
77   TemplateInfoIR template_info_ir;
78   for (auto &&template_element : template_info_protobuf.elements()) {
79     TemplateElementIR template_element_ir(template_element.referenced_type());
80     template_info_ir.AddTemplateElement(std::move(template_element_ir));
81   }
82   return template_info_ir;
83 }
84 
85 template< typename T>
SetupCFunctionLikeIR(const T & cfunction_like_protobuf,CFunctionLikeIR * cfunction_like_ir)86 static void SetupCFunctionLikeIR(const T &cfunction_like_protobuf,
87                                  CFunctionLikeIR *cfunction_like_ir) {
88   cfunction_like_ir->SetReturnType(cfunction_like_protobuf.return_type());
89   for (auto &&parameter: cfunction_like_protobuf.parameters()) {
90     ParamIR param_ir(parameter.referenced_type(), parameter.default_arg(),
91                      false);
92     cfunction_like_ir->AddParameter(std::move(param_ir));
93   }
94 }
95 
FunctionProtobufToIR(const abi_dump::FunctionDecl & function_protobuf)96 FunctionIR ProtobufTextFormatToIRReader::FunctionProtobufToIR(
97     const abi_dump::FunctionDecl &function_protobuf) {
98   FunctionIR function_ir;
99   function_ir.SetReturnType(function_protobuf.return_type());
100   function_ir.SetLinkerSetKey(function_protobuf.linker_set_key());
101   function_ir.SetName(function_protobuf.function_name());
102   function_ir.SetAccess(AccessProtobufToIR(function_protobuf.access()));
103   function_ir.SetSourceFile(function_protobuf.source_file());
104   // Set parameters
105   for (auto &&parameter: function_protobuf.parameters()) {
106     ParamIR param_ir(parameter.referenced_type(), parameter.default_arg(),
107                      parameter.is_this_ptr());
108     function_ir.AddParameter(std::move(param_ir));
109   }
110   // Set Template info
111   function_ir.SetTemplateInfo(
112       TemplateInfoProtobufToIR(function_protobuf.template_info()));
113   return function_ir;
114 }
115 
FunctionTypeProtobufToIR(const abi_dump::FunctionType & function_type_protobuf)116 FunctionTypeIR ProtobufTextFormatToIRReader::FunctionTypeProtobufToIR(
117     const abi_dump::FunctionType &function_type_protobuf) {
118   FunctionTypeIR function_type_ir;
119   ReadTypeInfo(function_type_protobuf.type_info(), &function_type_ir);
120   SetupCFunctionLikeIR(function_type_protobuf, &function_type_ir);
121   return function_type_ir;
122 }
123 
VTableLayoutProtobufToIR(const abi_dump::VTableLayout & vtable_layout_protobuf)124 VTableLayoutIR ProtobufTextFormatToIRReader::VTableLayoutProtobufToIR(
125     const abi_dump::VTableLayout &vtable_layout_protobuf) {
126   VTableLayoutIR vtable_layout_ir;
127   for (auto &&vtable_component : vtable_layout_protobuf.vtable_components()) {
128     VTableComponentIR vtable_component_ir(
129         vtable_component.mangled_component_name(),
130         VTableComponentKindProtobufToIR(vtable_component.kind()),
131         vtable_component.component_value());
132     vtable_layout_ir.AddVTableComponent(std::move(vtable_component_ir));
133   }
134   return vtable_layout_ir;
135 }
136 
137 std::vector<RecordFieldIR>
RecordFieldsProtobufToIR(const google::protobuf::RepeatedPtrField<abi_dump::RecordFieldDecl> & rfp)138 ProtobufTextFormatToIRReader::RecordFieldsProtobufToIR(
139     const google::protobuf::RepeatedPtrField<abi_dump::RecordFieldDecl> &rfp) {
140   std::vector<RecordFieldIR> record_type_fields_ir;
141   for (auto &&field : rfp) {
142     RecordFieldIR record_field_ir(field.field_name(), field.referenced_type(),
143                                   field.field_offset(),
144                                   AccessProtobufToIR(field.access()));
145     record_type_fields_ir.emplace_back(std::move(record_field_ir));
146   }
147   return record_type_fields_ir;
148 }
149 
150 std::vector<CXXBaseSpecifierIR>
RecordCXXBaseSpecifiersProtobufToIR(const google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> & rbs)151 ProtobufTextFormatToIRReader::RecordCXXBaseSpecifiersProtobufToIR(
152     const google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> &rbs) {
153   std::vector<CXXBaseSpecifierIR> record_type_bases_ir;
154   for (auto &&base : rbs) {
155     CXXBaseSpecifierIR record_base_ir(
156         base.referenced_type(), base.is_virtual(),
157         AccessProtobufToIR(base.access()));
158     record_type_bases_ir.emplace_back(std::move(record_base_ir));
159   }
160   return record_type_bases_ir;
161 }
162 
RecordTypeProtobufToIR(const abi_dump::RecordType & record_type_protobuf)163 RecordTypeIR ProtobufTextFormatToIRReader::RecordTypeProtobufToIR(
164     const abi_dump::RecordType &record_type_protobuf) {
165   RecordTypeIR record_type_ir;
166   ReadTypeInfo(record_type_protobuf.type_info(), &record_type_ir);
167   record_type_ir.SetTemplateInfo(
168       TemplateInfoProtobufToIR(record_type_protobuf.template_info()));
169   record_type_ir.SetAccess(AccessProtobufToIR(record_type_protobuf.access()));
170   record_type_ir.SetVTableLayout(
171       VTableLayoutProtobufToIR(record_type_protobuf.vtable_layout()));
172   // Get fields
173   record_type_ir.SetRecordFields(RecordFieldsProtobufToIR(
174       record_type_protobuf.fields()));
175   // Base Specifiers
176   record_type_ir.SetCXXBaseSpecifiers(RecordCXXBaseSpecifiersProtobufToIR(
177       record_type_protobuf.base_specifiers()));
178   record_type_ir.SetRecordKind(
179       RecordKindProtobufToIR(record_type_protobuf.record_kind()));
180   record_type_ir.SetAnonymity(record_type_protobuf.is_anonymous());
181   record_type_ir.SetUniqueId(record_type_protobuf.tag_info().unique_id());
182   return record_type_ir;
183 }
184 
185 std::vector<EnumFieldIR>
EnumFieldsProtobufToIR(const google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> & efp)186 ProtobufTextFormatToIRReader::EnumFieldsProtobufToIR(
187     const google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> &efp) {
188   std::vector<EnumFieldIR> enum_type_fields_ir;
189   for (auto &&field : efp) {
190     EnumFieldIR enum_field_ir(field.name(), field.enum_field_value());
191     enum_type_fields_ir.emplace_back(std::move(enum_field_ir));
192   }
193   return enum_type_fields_ir;
194 }
195 
EnumTypeProtobufToIR(const abi_dump::EnumType & enum_type_protobuf)196 EnumTypeIR ProtobufTextFormatToIRReader::EnumTypeProtobufToIR(
197     const abi_dump::EnumType &enum_type_protobuf) {
198   EnumTypeIR enum_type_ir;
199   ReadTypeInfo(enum_type_protobuf.type_info(), &enum_type_ir);
200   enum_type_ir.SetUnderlyingType(enum_type_protobuf.underlying_type());
201   enum_type_ir.SetAccess(AccessProtobufToIR(enum_type_protobuf.access()));
202   enum_type_ir.SetFields(
203       EnumFieldsProtobufToIR(enum_type_protobuf.enum_fields()));
204   enum_type_ir.SetUniqueId(enum_type_protobuf.tag_info().unique_id());
205   return enum_type_ir;
206 }
207 
ReadGlobalVariables(const abi_dump::TranslationUnit & tu)208 void ProtobufTextFormatToIRReader::ReadGlobalVariables(
209     const abi_dump::TranslationUnit &tu) {
210   for (auto &&global_variable_protobuf : tu.global_vars()) {
211     GlobalVarIR global_variable_ir;
212     global_variable_ir.SetName(global_variable_protobuf.name());
213     global_variable_ir.SetAccess(AccessProtobufToIR(global_variable_protobuf.access()));
214     global_variable_ir.SetSourceFile(global_variable_protobuf.source_file());
215     global_variable_ir.SetReferencedType(
216         global_variable_protobuf.referenced_type());
217     global_variable_ir.SetLinkerSetKey(
218         global_variable_protobuf.linker_set_key());
219     if (!IsPresentInExportedHeaders(global_variable_ir, exported_headers_)) {
220       continue;
221     }
222     global_variables_.insert(
223         {global_variable_ir.GetLinkerSetKey(), std::move(global_variable_ir)});
224   }
225 }
226 
ReadPointerTypes(const abi_dump::TranslationUnit & tu)227 void ProtobufTextFormatToIRReader::ReadPointerTypes(
228     const abi_dump::TranslationUnit &tu) {
229   for (auto &&pointer_type_protobuf : tu.pointer_types()) {
230     PointerTypeIR pointer_type_ir;
231     ReadTypeInfo(pointer_type_protobuf.type_info(), &pointer_type_ir);
232     if (!IsPresentInExportedHeaders(pointer_type_ir, exported_headers_)) {
233       continue;
234     }
235     AddToMapAndTypeGraph(std::move(pointer_type_ir), &pointer_types_,
236                          &type_graph_);
237   }
238 }
239 
ReadBuiltinTypes(const abi_dump::TranslationUnit & tu)240 void ProtobufTextFormatToIRReader::ReadBuiltinTypes(
241     const abi_dump::TranslationUnit &tu) {
242   for (auto &&builtin_type_protobuf : tu.builtin_types()) {
243     BuiltinTypeIR builtin_type_ir;
244     ReadTypeInfo(builtin_type_protobuf.type_info(), &builtin_type_ir);
245     builtin_type_ir.SetSignedness(builtin_type_protobuf.is_unsigned());
246     builtin_type_ir.SetIntegralType(builtin_type_protobuf.is_integral());
247     AddToMapAndTypeGraph(std::move(builtin_type_ir), &builtin_types_,
248                          &type_graph_);
249   }
250 }
251 
ReadQualifiedTypes(const abi_dump::TranslationUnit & tu)252 void ProtobufTextFormatToIRReader::ReadQualifiedTypes(
253     const abi_dump::TranslationUnit &tu) {
254   for (auto &&qualified_type_protobuf : tu.qualified_types()) {
255     QualifiedTypeIR qualified_type_ir;
256     ReadTypeInfo(qualified_type_protobuf.type_info(), &qualified_type_ir);
257     qualified_type_ir.SetConstness(qualified_type_protobuf.is_const());
258     qualified_type_ir.SetVolatility(qualified_type_protobuf.is_volatile());
259     qualified_type_ir.SetRestrictedness(
260         qualified_type_protobuf.is_restricted());
261     if (!IsPresentInExportedHeaders(qualified_type_ir, exported_headers_)) {
262       continue;
263     }
264     AddToMapAndTypeGraph(std::move(qualified_type_ir), &qualified_types_,
265                          &type_graph_);
266   }
267 }
268 
ReadArrayTypes(const abi_dump::TranslationUnit & tu)269 void ProtobufTextFormatToIRReader::ReadArrayTypes(
270     const abi_dump::TranslationUnit &tu) {
271   for (auto &&array_type_protobuf : tu.array_types()) {
272     ArrayTypeIR array_type_ir;
273     ReadTypeInfo(array_type_protobuf.type_info(), &array_type_ir);
274     if (!IsPresentInExportedHeaders(array_type_ir, exported_headers_)) {
275       continue;
276     }
277     AddToMapAndTypeGraph(std::move(array_type_ir), &array_types_,
278                          &type_graph_);
279   }
280 }
281 
ReadLvalueReferenceTypes(const abi_dump::TranslationUnit & tu)282 void ProtobufTextFormatToIRReader::ReadLvalueReferenceTypes(
283     const abi_dump::TranslationUnit &tu) {
284   for (auto &&lvalue_reference_type_protobuf : tu.lvalue_reference_types()) {
285     LvalueReferenceTypeIR lvalue_reference_type_ir;
286     ReadTypeInfo(lvalue_reference_type_protobuf.type_info(),
287                  &lvalue_reference_type_ir);
288     if (!IsPresentInExportedHeaders(lvalue_reference_type_ir,
289                                     exported_headers_)) {
290       continue;
291     }
292     AddToMapAndTypeGraph(std::move(lvalue_reference_type_ir),
293                          &lvalue_reference_types_, &type_graph_);
294   }
295 }
296 
ReadRvalueReferenceTypes(const abi_dump::TranslationUnit & tu)297 void ProtobufTextFormatToIRReader::ReadRvalueReferenceTypes(
298     const abi_dump::TranslationUnit &tu) {
299   for (auto &&rvalue_reference_type_protobuf : tu.rvalue_reference_types()) {
300     RvalueReferenceTypeIR rvalue_reference_type_ir;
301     ReadTypeInfo(rvalue_reference_type_protobuf.type_info(),
302                  &rvalue_reference_type_ir);
303     if (!IsPresentInExportedHeaders(rvalue_reference_type_ir,
304                                     exported_headers_)) {
305       continue;
306     }
307     AddToMapAndTypeGraph(std::move(rvalue_reference_type_ir),
308                          &rvalue_reference_types_, &type_graph_);
309   }
310 }
311 
ReadFunctions(const abi_dump::TranslationUnit & tu)312 void ProtobufTextFormatToIRReader::ReadFunctions(
313     const abi_dump::TranslationUnit &tu) {
314   for (auto &&function_protobuf : tu.functions()) {
315     FunctionIR function_ir = FunctionProtobufToIR(function_protobuf);
316     if (!IsPresentInExportedHeaders(function_ir, exported_headers_)) {
317       continue;
318     }
319     functions_.insert({function_ir.GetLinkerSetKey(), std::move(function_ir)});
320   }
321 }
322 
ReadRecordTypes(const abi_dump::TranslationUnit & tu)323 void ProtobufTextFormatToIRReader::ReadRecordTypes(
324     const abi_dump::TranslationUnit &tu) {
325   for (auto &&record_type_protobuf : tu.record_types()) {
326     RecordTypeIR record_type_ir = RecordTypeProtobufToIR(record_type_protobuf);
327     if (!IsPresentInExportedHeaders(record_type_ir, exported_headers_)) {
328       continue;
329     }
330     auto it = AddToMapAndTypeGraph(std::move(record_type_ir), &record_types_,
331                                    &type_graph_);
332     const std::string &key = GetODRListMapKey(&(it->second));
333     AddToODRListMap(key, &(it->second));
334   }
335 }
336 
ReadFunctionTypes(const abi_dump::TranslationUnit & tu)337 void ProtobufTextFormatToIRReader::ReadFunctionTypes(
338     const abi_dump::TranslationUnit &tu) {
339   for (auto &&function_type_protobuf : tu.function_types()) {
340     FunctionTypeIR function_type_ir =
341         FunctionTypeProtobufToIR(function_type_protobuf);
342     if (!IsPresentInExportedHeaders(function_type_ir, exported_headers_)) {
343       continue;
344     }
345     auto it = AddToMapAndTypeGraph(std::move(function_type_ir),
346                                    &function_types_, &type_graph_);
347     const std::string &key = GetODRListMapKey(&(it->second));
348     AddToODRListMap(key, &(it->second));
349   }
350 }
351 
ReadEnumTypes(const abi_dump::TranslationUnit & tu)352 void ProtobufTextFormatToIRReader::ReadEnumTypes(
353     const abi_dump::TranslationUnit &tu) {
354   for (auto &&enum_type_protobuf : tu.enum_types()) {
355     EnumTypeIR enum_type_ir = EnumTypeProtobufToIR(enum_type_protobuf);
356     if (!IsPresentInExportedHeaders(enum_type_ir, exported_headers_)) {
357       continue;
358     }
359     auto it = AddToMapAndTypeGraph(std::move(enum_type_ir), &enum_types_,
360                                    &type_graph_);
361     AddToODRListMap(it->second.GetUniqueId() + it->second.GetSourceFile(),
362                     (&it->second));
363   }
364 }
365 
ReadElfFunctions(const abi_dump::TranslationUnit & tu)366 void ProtobufTextFormatToIRReader::ReadElfFunctions(
367     const abi_dump::TranslationUnit &tu) {
368   for (auto &&elf_function : tu.elf_functions()) {
369     ElfFunctionIR elf_function_ir(elf_function.name());
370     elf_functions_.insert(
371         {elf_function_ir.GetName(), std::move(elf_function_ir)});
372   }
373 }
374 
ReadElfObjects(const abi_dump::TranslationUnit & tu)375 void ProtobufTextFormatToIRReader::ReadElfObjects(
376     const abi_dump::TranslationUnit &tu) {
377   for (auto &&elf_object : tu.elf_objects()) {
378     ElfObjectIR elf_object_ir(elf_object.name());
379     elf_objects_.insert(
380         {elf_object_ir.GetName(), std::move(elf_object_ir)});
381   }
382 }
383 
AddTemplateInformation(abi_dump::TemplateInfo * ti,const abi_util::TemplatedArtifactIR * ta)384 bool IRToProtobufConverter::AddTemplateInformation(
385     abi_dump::TemplateInfo *ti, const abi_util::TemplatedArtifactIR *ta) {
386   for (auto &&template_element : ta->GetTemplateElements()) {
387     abi_dump::TemplateElement *added_element = ti->add_elements();
388     if (!added_element) {
389       llvm::errs() << "Failed to add template element\n";
390       return false;
391     }
392     added_element->set_referenced_type(template_element.GetReferencedType());
393   }
394   return true;
395 }
396 
AddTypeInfo(abi_dump::BasicNamedAndTypedDecl * type_info,const TypeIR * typep)397 bool IRToProtobufConverter::AddTypeInfo(
398     abi_dump::BasicNamedAndTypedDecl *type_info,
399     const TypeIR *typep) {
400   if (!type_info || !typep) {
401     llvm::errs() << "Typeinfo not valid\n";
402     return false;
403   }
404   type_info->set_linker_set_key(typep->GetLinkerSetKey());
405   type_info->set_source_file(typep->GetSourceFile());
406   type_info->set_name(typep->GetName());
407   type_info->set_size(typep->GetSize());
408   type_info->set_alignment(typep->GetAlignment());
409   type_info->set_referenced_type(typep->GetReferencedType());
410   type_info->set_self_type(typep->GetSelfType());
411   return true;
412 }
413 
SetIRToProtobufRecordField(abi_dump::RecordFieldDecl * record_field_protobuf,const RecordFieldIR * record_field_ir)414 static void SetIRToProtobufRecordField(
415     abi_dump::RecordFieldDecl *record_field_protobuf,
416     const RecordFieldIR *record_field_ir) {
417   record_field_protobuf->set_field_name(record_field_ir->GetName());
418   record_field_protobuf->set_referenced_type(
419       record_field_ir->GetReferencedType());
420   record_field_protobuf->set_access(
421       AccessIRToProtobuf(record_field_ir->GetAccess()));
422   record_field_protobuf->set_field_offset(record_field_ir->GetOffset());
423 }
424 
AddRecordFields(abi_dump::RecordType * record_protobuf,const RecordTypeIR * record_ir)425 bool IRToProtobufConverter::AddRecordFields(
426     abi_dump::RecordType *record_protobuf,
427     const RecordTypeIR *record_ir) {
428   // Iterate through the fields and create corresponding ones for the protobuf
429   // record
430   for (auto &&field_ir : record_ir->GetFields()) {
431     abi_dump::RecordFieldDecl *added_field = record_protobuf->add_fields();
432     if (!added_field) {
433       llvm::errs() << "Couldn't add record field\n";
434     }
435     SetIRToProtobufRecordField(added_field, &field_ir);
436   }
437   return true;
438 }
439 
SetIRToProtobufBaseSpecifier(abi_dump::CXXBaseSpecifier * base_specifier_protobuf,const CXXBaseSpecifierIR & base_specifier_ir)440 static bool SetIRToProtobufBaseSpecifier(
441     abi_dump::CXXBaseSpecifier *base_specifier_protobuf,
442     const CXXBaseSpecifierIR &base_specifier_ir) {
443   if (!base_specifier_protobuf) {
444     llvm::errs() << "Protobuf base specifier not valid\n";
445     return false;
446   }
447   base_specifier_protobuf->set_referenced_type(
448       base_specifier_ir.GetReferencedType());
449   base_specifier_protobuf->set_is_virtual(
450       base_specifier_ir.IsVirtual());
451   base_specifier_protobuf->set_access(
452       AccessIRToProtobuf(base_specifier_ir.GetAccess()));
453   return true;
454 }
455 
AddBaseSpecifiers(abi_dump::RecordType * record_protobuf,const RecordTypeIR * record_ir)456 bool IRToProtobufConverter::AddBaseSpecifiers(
457     abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir) {
458   for (auto &&base_ir : record_ir->GetBases()) {
459     abi_dump::CXXBaseSpecifier *added_base =
460         record_protobuf->add_base_specifiers();
461     if (!SetIRToProtobufBaseSpecifier(added_base, base_ir)) {
462       return false;
463     }
464   }
465   return true;
466 }
467 
SetIRToProtobufVTableLayout(abi_dump::VTableLayout * vtable_layout_protobuf,const VTableLayoutIR & vtable_layout_ir)468 static bool SetIRToProtobufVTableLayout(
469     abi_dump::VTableLayout *vtable_layout_protobuf,
470     const VTableLayoutIR &vtable_layout_ir) {
471   if (vtable_layout_protobuf == nullptr) {
472     llvm::errs() << "vtable layout protobuf not valid\n";
473     return false;
474   }
475   for (auto &&vtable_component_ir : vtable_layout_ir.GetVTableComponents()) {
476     abi_dump::VTableComponent *added_vtable_component =
477         vtable_layout_protobuf->add_vtable_components();
478     if (!added_vtable_component) {
479       llvm::errs() << "Couldn't add vtable component\n";
480       return false;
481     }
482     added_vtable_component->set_kind(
483         VTableComponentKindIRToProtobuf(vtable_component_ir.GetKind()));
484     added_vtable_component->set_component_value(vtable_component_ir.GetValue());
485     added_vtable_component->set_mangled_component_name(
486         vtable_component_ir.GetName());
487   }
488   return true;
489 }
490 
AddVTableLayout(abi_dump::RecordType * record_protobuf,const RecordTypeIR * record_ir)491 bool IRToProtobufConverter::AddVTableLayout(
492     abi_dump::RecordType *record_protobuf,
493     const RecordTypeIR *record_ir) {
494   // If there are no entries in the vtable, just return.
495   if (record_ir->GetVTableNumEntries() == 0) {
496     return true;
497   }
498   const VTableLayoutIR &vtable_layout_ir = record_ir->GetVTableLayout();
499   abi_dump::VTableLayout *vtable_layout_protobuf =
500       record_protobuf->mutable_vtable_layout();
501   if (!SetIRToProtobufVTableLayout(vtable_layout_protobuf, vtable_layout_ir)) {
502     return false;
503   }
504   return true;
505 }
506 
AddTagTypeInfo(abi_dump::TagType * tag_type_protobuf,const abi_util::TagTypeIR * tag_type_ir)507 bool IRToProtobufConverter::AddTagTypeInfo(
508     abi_dump::TagType *tag_type_protobuf,
509     const abi_util::TagTypeIR *tag_type_ir) {
510   if (!tag_type_protobuf || !tag_type_ir) {
511     return false;
512   }
513   tag_type_protobuf->set_unique_id(tag_type_ir->GetUniqueId());
514   return true;
515 }
516 
ConvertRecordTypeIR(const RecordTypeIR * recordp)517 abi_dump::RecordType IRToProtobufConverter::ConvertRecordTypeIR(
518     const RecordTypeIR *recordp) {
519   abi_dump::RecordType added_record_type;
520   added_record_type.set_access(AccessIRToProtobuf(recordp->GetAccess()));
521   added_record_type.set_record_kind(
522       RecordKindIRToProtobuf(recordp->GetRecordKind()));
523   if (recordp->IsAnonymous()) {
524     added_record_type.set_is_anonymous(true);
525   }
526   if (!AddTypeInfo(added_record_type.mutable_type_info(), recordp) ||
527       !AddRecordFields(&added_record_type, recordp) ||
528       !AddBaseSpecifiers(&added_record_type, recordp) ||
529       !AddVTableLayout(&added_record_type, recordp) ||
530       !AddTagTypeInfo(added_record_type.mutable_tag_info(), recordp) ||
531       !(recordp->GetTemplateElements().size() ?
532        AddTemplateInformation(added_record_type.mutable_template_info(),
533                               recordp) : true)) {
534     llvm::errs() << "Template information could not be added\n";
535     ::exit(1);
536   }
537   return added_record_type;
538 }
539 
540 
ConvertElfObjectIR(const ElfObjectIR * elf_object_ir)541 abi_dump::ElfObject IRToProtobufConverter::ConvertElfObjectIR(
542     const ElfObjectIR *elf_object_ir) {
543   abi_dump::ElfObject elf_object_protobuf;
544   elf_object_protobuf.set_name(elf_object_ir->GetName());
545   return elf_object_protobuf;
546 }
547 
ConvertElfFunctionIR(const ElfFunctionIR * elf_function_ir)548 abi_dump::ElfFunction IRToProtobufConverter::ConvertElfFunctionIR(
549     const ElfFunctionIR *elf_function_ir) {
550   abi_dump::ElfFunction elf_function_protobuf;
551   elf_function_protobuf.set_name(elf_function_ir->GetName());
552   return elf_function_protobuf;
553 }
554 
555 template <typename CFunctionLikeMessage>
AddFunctionParametersAndSetReturnType(CFunctionLikeMessage * function_like_protobuf,const CFunctionLikeIR * cfunction_like_ir)556 bool IRToProtobufConverter::AddFunctionParametersAndSetReturnType(
557     CFunctionLikeMessage *function_like_protobuf,
558     const CFunctionLikeIR *cfunction_like_ir) {
559   function_like_protobuf->set_return_type(cfunction_like_ir->GetReturnType());
560   return AddFunctionParameters(function_like_protobuf, cfunction_like_ir);
561 }
562 
563 template <typename CFunctionLikeMessage>
AddFunctionParameters(CFunctionLikeMessage * function_like_protobuf,const CFunctionLikeIR * cfunction_like_ir)564 bool IRToProtobufConverter::AddFunctionParameters(
565     CFunctionLikeMessage *function_like_protobuf,
566     const CFunctionLikeIR *cfunction_like_ir) {
567   for (auto &&parameter : cfunction_like_ir->GetParameters()) {
568     abi_dump::ParamDecl *added_parameter =
569         function_like_protobuf->add_parameters();
570     if (!added_parameter) {
571       return false;
572     }
573     added_parameter->set_referenced_type(
574         parameter.GetReferencedType());
575     added_parameter->set_default_arg(parameter.GetIsDefault());
576     added_parameter->set_is_this_ptr(parameter.GetIsThisPtr());
577   }
578   return true;
579 }
580 
ConvertFunctionTypeIR(const FunctionTypeIR * function_typep)581 abi_dump::FunctionType IRToProtobufConverter::ConvertFunctionTypeIR (
582     const FunctionTypeIR *function_typep) {
583   abi_dump::FunctionType added_function_type;
584   if (!AddTypeInfo(added_function_type.mutable_type_info(), function_typep) ||
585       !AddFunctionParametersAndSetReturnType(&added_function_type,
586                                              function_typep)) {
587     llvm::errs() << "Could not convert FunctionTypeIR to protobuf\n";
588     ::exit(1);
589   }
590   return added_function_type;
591 }
592 
ConvertFunctionIR(const FunctionIR * functionp)593 abi_dump::FunctionDecl IRToProtobufConverter::ConvertFunctionIR(
594     const FunctionIR *functionp) {
595   abi_dump::FunctionDecl added_function;
596   added_function.set_access(AccessIRToProtobuf(functionp->GetAccess()));
597   added_function.set_linker_set_key(functionp->GetLinkerSetKey());
598   added_function.set_source_file(functionp->GetSourceFile());
599   added_function.set_function_name(functionp->GetName());
600   if (!AddFunctionParametersAndSetReturnType(&added_function, functionp) ||
601       !(functionp->GetTemplateElements().size() ?
602       AddTemplateInformation(added_function.mutable_template_info(), functionp)
603       : true)) {
604     llvm::errs() << "Template information could not be added\n";
605     ::exit(1);
606   }
607   return added_function;
608 }
609 
SetIRToProtobufEnumField(abi_dump::EnumFieldDecl * enum_field_protobuf,const EnumFieldIR * enum_field_ir)610 static bool SetIRToProtobufEnumField(
611     abi_dump::EnumFieldDecl *enum_field_protobuf,
612     const EnumFieldIR *enum_field_ir) {
613   if (enum_field_protobuf == nullptr) {
614     return true;
615   }
616   enum_field_protobuf->set_name(enum_field_ir->GetName());
617   enum_field_protobuf->set_enum_field_value(enum_field_ir->GetValue());
618   return true;
619 }
620 
AddEnumFields(abi_dump::EnumType * enum_protobuf,const EnumTypeIR * enum_ir)621 bool IRToProtobufConverter::AddEnumFields(abi_dump::EnumType *enum_protobuf,
622                                      const EnumTypeIR *enum_ir) {
623   for (auto &&field : enum_ir->GetFields()) {
624     abi_dump::EnumFieldDecl *enum_fieldp = enum_protobuf->add_enum_fields();
625     if (!SetIRToProtobufEnumField(enum_fieldp, &field)) {
626       return false;
627     }
628   }
629   return true;
630 }
631 
632 
ConvertEnumTypeIR(const EnumTypeIR * enump)633 abi_dump::EnumType IRToProtobufConverter::ConvertEnumTypeIR(
634     const EnumTypeIR *enump) {
635   abi_dump::EnumType added_enum_type;
636   added_enum_type.set_access(AccessIRToProtobuf(enump->GetAccess()));
637   added_enum_type.set_underlying_type(enump->GetUnderlyingType());
638   if (!AddTypeInfo(added_enum_type.mutable_type_info(), enump) ||
639       !AddEnumFields(&added_enum_type, enump) ||
640       !AddTagTypeInfo(added_enum_type.mutable_tag_info(), enump)) {
641     llvm::errs() << "EnumTypeIR could not be converted\n";
642     ::exit(1);
643   }
644   return added_enum_type;
645 }
646 
ConvertGlobalVarIR(const GlobalVarIR * global_varp)647 abi_dump::GlobalVarDecl IRToProtobufConverter::ConvertGlobalVarIR(
648     const GlobalVarIR *global_varp) {
649   abi_dump::GlobalVarDecl added_global_var;
650   added_global_var.set_referenced_type(global_varp->GetReferencedType());
651   added_global_var.set_source_file(global_varp->GetSourceFile());
652   added_global_var.set_name(global_varp->GetName());
653   added_global_var.set_linker_set_key(global_varp->GetLinkerSetKey());
654   added_global_var.set_access(
655       AccessIRToProtobuf(global_varp->GetAccess()));
656   return added_global_var;
657 }
658 
ConvertPointerTypeIR(const PointerTypeIR * pointerp)659 abi_dump::PointerType IRToProtobufConverter::ConvertPointerTypeIR(
660     const PointerTypeIR *pointerp) {
661   abi_dump::PointerType added_pointer_type;
662   if (!AddTypeInfo(added_pointer_type.mutable_type_info(), pointerp)) {
663     llvm::errs() << "PointerTypeIR could not be converted\n";
664     ::exit(1);
665   }
666   return added_pointer_type;
667 }
668 
ConvertQualifiedTypeIR(const QualifiedTypeIR * qualtypep)669 abi_dump::QualifiedType IRToProtobufConverter::ConvertQualifiedTypeIR(
670     const QualifiedTypeIR *qualtypep) {
671   abi_dump::QualifiedType added_qualified_type;
672   if (!AddTypeInfo(added_qualified_type.mutable_type_info(), qualtypep)) {
673     llvm::errs() << "QualifiedTypeIR could not be converted\n";
674     ::exit(1);
675   }
676   added_qualified_type.set_is_const(qualtypep->IsConst());
677   added_qualified_type.set_is_volatile(qualtypep->IsVolatile());
678   added_qualified_type.set_is_restricted(qualtypep->IsRestricted());
679   return added_qualified_type;
680 }
681 
ConvertBuiltinTypeIR(const BuiltinTypeIR * builtin_typep)682 abi_dump::BuiltinType IRToProtobufConverter::ConvertBuiltinTypeIR(
683     const BuiltinTypeIR *builtin_typep) {
684   abi_dump::BuiltinType added_builtin_type;
685   added_builtin_type.set_is_unsigned(builtin_typep->IsUnsigned());
686   added_builtin_type.set_is_integral(builtin_typep->IsIntegralType());
687   if (!AddTypeInfo(added_builtin_type.mutable_type_info(), builtin_typep)) {
688     llvm::errs() << "BuiltinTypeIR could not be converted\n";
689     ::exit(1);
690   }
691   return added_builtin_type;
692 }
693 
ConvertArrayTypeIR(const ArrayTypeIR * array_typep)694 abi_dump::ArrayType IRToProtobufConverter::ConvertArrayTypeIR(
695     const ArrayTypeIR *array_typep) {
696   abi_dump::ArrayType added_array_type;
697   if (!AddTypeInfo(added_array_type.mutable_type_info(), array_typep)) {
698     llvm::errs() << "ArrayTypeIR could not be converted\n";
699     ::exit(1);
700   }
701   return added_array_type;
702 }
703 
704 abi_dump::LvalueReferenceType
ConvertLvalueReferenceTypeIR(const LvalueReferenceTypeIR * lvalue_reference_typep)705 IRToProtobufConverter::ConvertLvalueReferenceTypeIR(
706     const LvalueReferenceTypeIR *lvalue_reference_typep) {
707   abi_dump::LvalueReferenceType added_lvalue_reference_type;
708   if (!AddTypeInfo(added_lvalue_reference_type.mutable_type_info(),
709                    lvalue_reference_typep)) {
710     llvm::errs() << "LvalueReferenceTypeIR could not be converted\n";
711     ::exit(1);
712   }
713   return added_lvalue_reference_type;
714 }
715 
716 abi_dump::RvalueReferenceType
ConvertRvalueReferenceTypeIR(const RvalueReferenceTypeIR * rvalue_reference_typep)717 IRToProtobufConverter::ConvertRvalueReferenceTypeIR(
718     const RvalueReferenceTypeIR *rvalue_reference_typep) {
719   abi_dump::RvalueReferenceType added_rvalue_reference_type;
720   if (!AddTypeInfo(added_rvalue_reference_type.mutable_type_info(),
721                    rvalue_reference_typep)) {
722     llvm::errs() << "RvalueReferenceTypeIR could not be converted\n";
723     ::exit(1);
724   }
725   return added_rvalue_reference_type;
726 }
727 
728 
AddTypeInfoDiff(abi_diff::TypeInfoDiff * type_info_diff_protobuf,const TypeDiffIR * type_diff_ir)729 bool IRDiffToProtobufConverter::AddTypeInfoDiff(
730     abi_diff::TypeInfoDiff *type_info_diff_protobuf,
731     const TypeDiffIR *type_diff_ir) {
732   abi_diff::TypeInfo *old_type_info_protobuf =
733       type_info_diff_protobuf->mutable_old_type_info();
734   abi_diff::TypeInfo *new_type_info_protobuf =
735       type_info_diff_protobuf->mutable_new_type_info();
736   if (old_type_info_protobuf == nullptr || new_type_info_protobuf == nullptr) {
737     return false;
738   }
739   const std::pair<uint64_t, uint64_t> &sizes = type_diff_ir->GetSizes();
740   const std::pair<uint32_t, uint32_t> &alignments =
741       type_diff_ir->GetAlignments();
742   old_type_info_protobuf->set_size(sizes.first);
743   new_type_info_protobuf->set_size(sizes.second);
744 
745   old_type_info_protobuf->set_alignment(alignments.first);
746   new_type_info_protobuf->set_alignment(alignments.second);
747   return true;
748 }
749 
AddVTableLayoutDiff(abi_diff::VTableLayoutDiff * vtable_layout_diff_protobuf,const VTableLayoutDiffIR * vtable_layout_diff_ir)750 bool IRDiffToProtobufConverter::AddVTableLayoutDiff(
751     abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf,
752     const VTableLayoutDiffIR *vtable_layout_diff_ir) {
753   abi_dump:: VTableLayout *old_vtable =
754       vtable_layout_diff_protobuf->mutable_old_vtable();
755   abi_dump:: VTableLayout *new_vtable =
756       vtable_layout_diff_protobuf->mutable_new_vtable();
757   if (old_vtable == nullptr || new_vtable == nullptr ||
758       !SetIRToProtobufVTableLayout(old_vtable,
759                                    vtable_layout_diff_ir->GetOldVTable()) ||
760       !SetIRToProtobufVTableLayout(new_vtable,
761                                    vtable_layout_diff_ir->GetNewVTable())) {
762     return false;
763   }
764   return true;
765 }
766 
767 template <typename T>
CopyBaseSpecifiersDiffIRToProtobuf(google::protobuf::RepeatedPtrField<T> * dst,const std::vector<CXXBaseSpecifierIR> & bases_ir)768 static bool CopyBaseSpecifiersDiffIRToProtobuf(
769     google::protobuf::RepeatedPtrField<T> *dst,
770     const std::vector<CXXBaseSpecifierIR> &bases_ir) {
771   for (auto &&base_ir : bases_ir) {
772     T *added_base = dst->Add();
773     if (!SetIRToProtobufBaseSpecifier(added_base, base_ir)) {
774       return false;
775     }
776   }
777   return true;
778 }
779 
AddBaseSpecifierDiffs(abi_diff::CXXBaseSpecifierDiff * base_specifiers_diff_protobuf,const CXXBaseSpecifierDiffIR * base_specifiers_diff_ir)780 bool IRDiffToProtobufConverter::AddBaseSpecifierDiffs(
781     abi_diff::CXXBaseSpecifierDiff *base_specifiers_diff_protobuf,
782     const CXXBaseSpecifierDiffIR *base_specifiers_diff_ir) {
783   if (!CopyBaseSpecifiersDiffIRToProtobuf(
784           base_specifiers_diff_protobuf->mutable_old_bases(),
785           base_specifiers_diff_ir->GetOldBases()) ||
786       !CopyBaseSpecifiersDiffIRToProtobuf(
787           base_specifiers_diff_protobuf->mutable_new_bases(),
788           base_specifiers_diff_ir->GetNewBases())) {
789     return false;
790   }
791   return true;
792 }
793 
AddRecordFields(abi_diff::RecordTypeDiff * record_diff_protobuf,const std::vector<const RecordFieldIR * > & record_fields_ir,bool field_removed)794 bool IRDiffToProtobufConverter::AddRecordFields(
795     abi_diff::RecordTypeDiff *record_diff_protobuf,
796     const std::vector<const RecordFieldIR *> &record_fields_ir,
797     bool field_removed) {
798   for (auto &&record_field_ir : record_fields_ir) {
799     abi_dump::RecordFieldDecl *field = nullptr;
800     if (field_removed) {
801       field = record_diff_protobuf->add_fields_removed();
802     } else {
803       field = record_diff_protobuf->add_fields_added();
804     }
805     if (field == nullptr) {
806       return false;
807     }
808     SetIRToProtobufRecordField(field, record_field_ir);
809   }
810   return true;
811 }
812 
AddRecordFieldDiffs(abi_diff::RecordTypeDiff * record_diff_protobuf,const std::vector<RecordFieldDiffIR> & record_field_diffs_ir)813 bool IRDiffToProtobufConverter::AddRecordFieldDiffs(
814     abi_diff::RecordTypeDiff *record_diff_protobuf,
815     const std::vector<RecordFieldDiffIR> &record_field_diffs_ir) {
816   for (auto &&record_field_diff_ir : record_field_diffs_ir) {
817     abi_diff::RecordFieldDeclDiff *record_field_diff =
818         record_diff_protobuf->add_fields_diff();
819     if (record_field_diff == nullptr) {
820       return false;
821     }
822     abi_dump::RecordFieldDecl *old_field =
823         record_field_diff->mutable_old_field();
824     abi_dump::RecordFieldDecl *new_field =
825         record_field_diff->mutable_new_field();
826     if (old_field == nullptr || new_field == nullptr) {
827       return false;
828     }
829     SetIRToProtobufRecordField(old_field,
830                                record_field_diff_ir.GetOldField());
831     SetIRToProtobufRecordField(new_field,
832                                record_field_diff_ir.GetNewField());
833   }
834   return true;
835 }
836 
ConvertRecordTypeDiffIR(const RecordTypeDiffIR * record_type_diff_ir)837 abi_diff::RecordTypeDiff IRDiffToProtobufConverter::ConvertRecordTypeDiffIR(
838     const RecordTypeDiffIR *record_type_diff_ir) {
839   abi_diff::RecordTypeDiff record_type_diff_protobuf;
840   record_type_diff_protobuf.set_name(record_type_diff_ir->GetName());
841   const TypeDiffIR *type_diff_ir = record_type_diff_ir->GetTypeDiff();
842   // If a type_info diff exists
843   if (type_diff_ir != nullptr) {
844     abi_diff::TypeInfoDiff *type_info_diff =
845         record_type_diff_protobuf.mutable_type_info_diff();
846     if (!AddTypeInfoDiff(type_info_diff, type_diff_ir)) {
847         llvm::errs() << "RecordType could not be converted\n";
848        ::exit(1);
849     }
850   }
851   // If vtables differ.
852   const VTableLayoutDiffIR *vtable_layout_diff_ir =
853       record_type_diff_ir->GetVTableLayoutDiff();
854   if (vtable_layout_diff_ir != nullptr) {
855     abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf =
856         record_type_diff_protobuf.mutable_vtable_layout_diff();
857     if (!AddVTableLayoutDiff(vtable_layout_diff_protobuf,
858                              vtable_layout_diff_ir)) {
859       llvm::errs() << "VTable layout diff could not be added\n";
860       ::exit(1);
861     }
862   }
863   // If base specifiers differ.
864   const CXXBaseSpecifierDiffIR *base_specifier_diff_ir =
865       record_type_diff_ir->GetBaseSpecifiers();
866   if ( base_specifier_diff_ir != nullptr) {
867     abi_diff::CXXBaseSpecifierDiff *base_specifier_diff_protobuf =
868         record_type_diff_protobuf.mutable_bases_diff();
869     if (!AddBaseSpecifierDiffs(base_specifier_diff_protobuf,
870                                base_specifier_diff_ir)) {
871       llvm::errs() << "Base Specifier diff could not be added\n";
872       ::exit(1);
873     }
874   }
875   // Field diffs
876   if (!AddRecordFields(&record_type_diff_protobuf,
877                        record_type_diff_ir->GetFieldsRemoved(), true) ||
878       !AddRecordFields(&record_type_diff_protobuf,
879                        record_type_diff_ir->GetFieldsAdded(), false) ||
880       !AddRecordFieldDiffs(&record_type_diff_protobuf,
881                            record_type_diff_ir->GetFieldDiffs())) {
882     llvm::errs() << "Record Field diff could not be added\n";
883     ::exit(1);
884   }
885   return record_type_diff_protobuf;
886 }
887 
AddEnumUnderlyingTypeDiff(abi_diff::UnderlyingTypeDiff * underlying_type_diff_protobuf,const std::pair<std::string,std::string> * underlying_type_diff_ir)888 bool IRDiffToProtobufConverter::AddEnumUnderlyingTypeDiff(
889     abi_diff::UnderlyingTypeDiff *underlying_type_diff_protobuf,
890     const std::pair<std::string, std::string> *underlying_type_diff_ir) {
891   if (underlying_type_diff_protobuf == nullptr) {
892     return false;
893   }
894   underlying_type_diff_protobuf->set_old_type(underlying_type_diff_ir->first);
895   underlying_type_diff_protobuf->set_new_type(underlying_type_diff_ir->second);
896   return true;
897 }
898 
AddEnumFields(google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> * dst,const std::vector<const EnumFieldIR * > & enum_fields)899 static bool AddEnumFields(
900     google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> *dst,
901     const std::vector<const EnumFieldIR *> &enum_fields) {
902   for (auto &&enum_field : enum_fields) {
903     abi_dump::EnumFieldDecl *added_enum_field = dst->Add();
904     if (!SetIRToProtobufEnumField(added_enum_field, enum_field)) {
905       return false;
906     }
907   }
908   return true;
909 }
910 
AddEnumFieldDiffs(google::protobuf::RepeatedPtrField<abi_diff::EnumFieldDeclDiff> * dst,const std::vector<EnumFieldDiffIR> & fields_diff_ir)911 static bool AddEnumFieldDiffs(
912     google::protobuf::RepeatedPtrField<abi_diff::EnumFieldDeclDiff> *dst,
913     const std::vector<EnumFieldDiffIR> &fields_diff_ir) {
914   for (auto &&field_diff_ir : fields_diff_ir) {
915     abi_diff::EnumFieldDeclDiff *field_diff_protobuf = dst->Add();
916     if (field_diff_protobuf == nullptr) {
917       return false;
918     }
919     if (!SetIRToProtobufEnumField(field_diff_protobuf->mutable_old_field(),
920                                   field_diff_ir.GetOldField()) ||
921         !SetIRToProtobufEnumField(field_diff_protobuf->mutable_new_field(),
922                                   field_diff_ir.GetNewField())) {
923       return false;
924     }
925   }
926   return true;
927 }
928 
ConvertEnumTypeDiffIR(const EnumTypeDiffIR * enum_type_diff_ir)929 abi_diff::EnumTypeDiff IRDiffToProtobufConverter::ConvertEnumTypeDiffIR(
930     const EnumTypeDiffIR *enum_type_diff_ir) {
931   abi_diff::EnumTypeDiff enum_type_diff_protobuf;
932   enum_type_diff_protobuf.set_name(enum_type_diff_ir->GetName());
933   const std::pair<std::string, std::string> *underlying_type_diff =
934       enum_type_diff_ir->GetUnderlyingTypeDiff();
935   if ((underlying_type_diff != nullptr &&
936       !AddEnumUnderlyingTypeDiff(
937           enum_type_diff_protobuf.mutable_underlying_type_diff(),
938           underlying_type_diff)) ||
939       !AddEnumFields(enum_type_diff_protobuf.mutable_fields_removed(),
940                      enum_type_diff_ir->GetFieldsRemoved()) ||
941       !AddEnumFields(enum_type_diff_protobuf.mutable_fields_added(),
942                      enum_type_diff_ir->GetFieldsAdded()) ||
943       !AddEnumFieldDiffs(enum_type_diff_protobuf.mutable_fields_diff(),
944                          enum_type_diff_ir->GetFieldsDiff())) {
945     llvm::errs() << "Enum field diff could not be added\n";
946     ::exit(1);
947   }
948   return enum_type_diff_protobuf;
949 }
950 
ConvertGlobalVarDiffIR(const GlobalVarDiffIR * global_var_diff_ir)951 abi_diff::GlobalVarDeclDiff IRDiffToProtobufConverter::ConvertGlobalVarDiffIR(
952     const GlobalVarDiffIR *global_var_diff_ir) {
953   abi_diff::GlobalVarDeclDiff global_var_diff;
954   global_var_diff.set_name(global_var_diff_ir->GetName());
955   abi_dump::GlobalVarDecl *old_global_var = global_var_diff.mutable_old();
956   abi_dump::GlobalVarDecl *new_global_var = global_var_diff.mutable_new_();
957   if (old_global_var == nullptr || new_global_var == nullptr) {
958     llvm::errs() << "Globar Var diff could not be added\n";
959     ::exit(1);
960   }
961   *old_global_var =
962       IRToProtobufConverter::ConvertGlobalVarIR(
963           global_var_diff_ir->GetOldGlobalVar());
964   *new_global_var =
965       IRToProtobufConverter::ConvertGlobalVarIR(
966           global_var_diff_ir->GetNewGlobalVar());
967   return global_var_diff;
968 }
969 
ConvertFunctionDiffIR(const FunctionDiffIR * function_diff_ir)970 abi_diff::FunctionDeclDiff IRDiffToProtobufConverter::ConvertFunctionDiffIR(
971     const FunctionDiffIR *function_diff_ir) {
972   abi_diff::FunctionDeclDiff function_diff;
973   function_diff.set_name(function_diff_ir->GetName());
974   abi_dump::FunctionDecl *old_function = function_diff.mutable_old();
975   abi_dump::FunctionDecl *new_function = function_diff.mutable_new_();
976   if (old_function == nullptr || new_function == nullptr) {
977     llvm::errs() << "Function diff could not be added\n";
978     ::exit(1);
979   }
980   *old_function =
981       IRToProtobufConverter::ConvertFunctionIR(
982           function_diff_ir->GetOldFunction());
983   *new_function =
984       IRToProtobufConverter::ConvertFunctionIR(
985           function_diff_ir->GetNewFunction());
986   return function_diff;
987 }
988 
AddLinkableMessageIR(const LinkableMessageIR * lm)989 bool ProtobufIRDumper::AddLinkableMessageIR (const LinkableMessageIR *lm) {
990   // No RTTI
991   switch (lm->GetKind()) {
992     case RecordTypeKind:
993       return AddRecordTypeIR(static_cast<const RecordTypeIR *>(lm));
994     case EnumTypeKind:
995       return AddEnumTypeIR(static_cast<const EnumTypeIR *>(lm));
996     case PointerTypeKind:
997       return AddPointerTypeIR(static_cast<const PointerTypeIR *>(lm));
998     case QualifiedTypeKind:
999       return AddQualifiedTypeIR(static_cast<const QualifiedTypeIR *>(lm));
1000     case ArrayTypeKind:
1001       return AddArrayTypeIR(static_cast<const ArrayTypeIR *>(lm));
1002     case LvalueReferenceTypeKind:
1003       return AddLvalueReferenceTypeIR(
1004           static_cast<const LvalueReferenceTypeIR *>(lm));
1005     case RvalueReferenceTypeKind:
1006       return AddRvalueReferenceTypeIR(
1007           static_cast<const RvalueReferenceTypeIR*>(lm));
1008     case BuiltinTypeKind:
1009       return AddBuiltinTypeIR(static_cast<const BuiltinTypeIR*>(lm));
1010     case FunctionTypeKind:
1011       return AddFunctionTypeIR(static_cast<const FunctionTypeIR*>(lm));
1012     case GlobalVarKind:
1013       return AddGlobalVarIR(static_cast<const GlobalVarIR*>(lm));
1014     case FunctionKind:
1015       return AddFunctionIR(static_cast<const FunctionIR*>(lm));
1016   }
1017   return false;
1018 }
1019 
AddElfFunctionIR(const ElfFunctionIR * elf_function)1020 bool ProtobufIRDumper::AddElfFunctionIR(const ElfFunctionIR *elf_function) {
1021   abi_dump::ElfFunction *added_elf_function = tu_ptr_->add_elf_functions();
1022   if (!added_elf_function) {
1023     return false;
1024   }
1025   added_elf_function->set_name(elf_function->GetName());
1026   return true;
1027 }
1028 
AddElfObjectIR(const ElfObjectIR * elf_object)1029 bool ProtobufIRDumper::AddElfObjectIR(const ElfObjectIR *elf_object) {
1030   abi_dump::ElfObject *added_elf_object = tu_ptr_->add_elf_objects();
1031   if (!added_elf_object) {
1032     return false;
1033   }
1034   added_elf_object->set_name(elf_object->GetName());
1035   return true;
1036 }
1037 
AddElfSymbolMessageIR(const ElfSymbolIR * em)1038 bool ProtobufIRDumper::AddElfSymbolMessageIR(const ElfSymbolIR *em) {
1039   switch (em->GetKind()) {
1040     case ElfSymbolIR::ElfFunctionKind:
1041       return AddElfFunctionIR(static_cast<const ElfFunctionIR *>(em));
1042     case ElfSymbolIR::ElfObjectKind:
1043       return AddElfObjectIR(static_cast<const ElfObjectIR *>(em));
1044   }
1045   return false;
1046 }
1047 
AddRecordTypeIR(const RecordTypeIR * recordp)1048 bool ProtobufIRDumper::AddRecordTypeIR(const RecordTypeIR *recordp) {
1049   abi_dump::RecordType *added_record_type = tu_ptr_->add_record_types();
1050   if (!added_record_type) {
1051     return false;
1052   }
1053   *added_record_type = ConvertRecordTypeIR(recordp);
1054   return true;
1055 }
1056 
AddFunctionTypeIR(const FunctionTypeIR * function_typep)1057 bool ProtobufIRDumper::AddFunctionTypeIR(const FunctionTypeIR *function_typep) {
1058   abi_dump::FunctionType *added_function_type = tu_ptr_->add_function_types();
1059   if (!added_function_type) {
1060     return false;
1061   }
1062   *added_function_type = ConvertFunctionTypeIR(function_typep);
1063   return true;
1064 }
1065 
AddFunctionIR(const FunctionIR * functionp)1066 bool ProtobufIRDumper::AddFunctionIR(const FunctionIR *functionp) {
1067   abi_dump::FunctionDecl *added_function = tu_ptr_->add_functions();
1068   if (!added_function) {
1069     return false;
1070   }
1071   *added_function = ConvertFunctionIR(functionp);
1072   return true;
1073 }
1074 
AddEnumTypeIR(const EnumTypeIR * enump)1075 bool ProtobufIRDumper::AddEnumTypeIR(const EnumTypeIR *enump) {
1076   abi_dump::EnumType *added_enum_type = tu_ptr_->add_enum_types();
1077   if (!added_enum_type) {
1078     return false;
1079   }
1080   *added_enum_type = ConvertEnumTypeIR(enump);
1081   return true;
1082 }
1083 
AddGlobalVarIR(const GlobalVarIR * global_varp)1084 bool ProtobufIRDumper::AddGlobalVarIR(const GlobalVarIR *global_varp) {
1085   abi_dump::GlobalVarDecl *added_global_var = tu_ptr_->add_global_vars();
1086   if (!added_global_var) {
1087     return false;
1088   }
1089   *added_global_var = ConvertGlobalVarIR(global_varp);
1090   return true;
1091 }
1092 
AddPointerTypeIR(const PointerTypeIR * pointerp)1093 bool ProtobufIRDumper::AddPointerTypeIR(const PointerTypeIR *pointerp) {
1094   abi_dump::PointerType *added_pointer_type = tu_ptr_->add_pointer_types();
1095   if (!added_pointer_type) {
1096     return false;
1097   }
1098   *added_pointer_type = ConvertPointerTypeIR(pointerp);
1099   return true;
1100 }
1101 
AddQualifiedTypeIR(const QualifiedTypeIR * qualtypep)1102 bool ProtobufIRDumper::AddQualifiedTypeIR(const QualifiedTypeIR *qualtypep) {
1103   abi_dump::QualifiedType *added_qualified_type =
1104       tu_ptr_->add_qualified_types();
1105   if (!added_qualified_type) {
1106     return false;
1107   }
1108   *added_qualified_type = ConvertQualifiedTypeIR(qualtypep);
1109   return true;
1110 }
1111 
AddBuiltinTypeIR(const BuiltinTypeIR * builtin_typep)1112 bool ProtobufIRDumper::AddBuiltinTypeIR(const BuiltinTypeIR *builtin_typep) {
1113   abi_dump::BuiltinType *added_builtin_type =
1114       tu_ptr_->add_builtin_types();
1115   if (!added_builtin_type) {
1116     return false;
1117   }
1118   *added_builtin_type = ConvertBuiltinTypeIR(builtin_typep);
1119   return true;
1120 }
1121 
AddArrayTypeIR(const ArrayTypeIR * array_typep)1122 bool ProtobufIRDumper::AddArrayTypeIR(const ArrayTypeIR *array_typep) {
1123   abi_dump::ArrayType *added_array_type =
1124       tu_ptr_->add_array_types();
1125   if (!added_array_type) {
1126     return false;
1127   }
1128   *added_array_type = ConvertArrayTypeIR(array_typep);
1129   return true;
1130 }
1131 
AddLvalueReferenceTypeIR(const LvalueReferenceTypeIR * lvalue_reference_typep)1132 bool ProtobufIRDumper::AddLvalueReferenceTypeIR(
1133     const LvalueReferenceTypeIR *lvalue_reference_typep) {
1134   abi_dump::LvalueReferenceType *added_lvalue_reference_type =
1135       tu_ptr_->add_lvalue_reference_types();
1136   if (!added_lvalue_reference_type) {
1137     return false;
1138   }
1139   *added_lvalue_reference_type =
1140       ConvertLvalueReferenceTypeIR(lvalue_reference_typep);
1141   return true;
1142 }
1143 
AddRvalueReferenceTypeIR(const RvalueReferenceTypeIR * rvalue_reference_typep)1144 bool ProtobufIRDumper::AddRvalueReferenceTypeIR(
1145     const RvalueReferenceTypeIR *rvalue_reference_typep) {
1146   abi_dump::RvalueReferenceType *added_rvalue_reference_type =
1147       tu_ptr_->add_rvalue_reference_types();
1148   if (!added_rvalue_reference_type) {
1149     return false;
1150   }
1151   *added_rvalue_reference_type =
1152       ConvertRvalueReferenceTypeIR(rvalue_reference_typep);
1153   return true;
1154 }
1155 
Dump()1156 bool ProtobufIRDumper::Dump() {
1157   GOOGLE_PROTOBUF_VERIFY_VERSION;
1158   assert( tu_ptr_.get() != nullptr);
1159   std::ofstream text_output(dump_path_);
1160   google::protobuf::io::OstreamOutputStream text_os(&text_output);
1161   return google::protobuf::TextFormat::Print(*tu_ptr_.get(), &text_os);
1162 }
1163 
AddLibNameIR(const std::string & name)1164 void ProtobufIRDiffDumper::AddLibNameIR(const std::string &name) {
1165   diff_tu_->set_lib_name(name);
1166 }
1167 
AddArchIR(const std::string & arch)1168 void ProtobufIRDiffDumper::AddArchIR(const std::string &arch) {
1169   diff_tu_->set_arch(arch);
1170 }
1171 
GetCompatibilityStatusIR()1172 CompatibilityStatusIR ProtobufIRDiffDumper::GetCompatibilityStatusIR() {
1173   if (diff_tu_->functions_removed().size() != 0 ||
1174       diff_tu_->global_vars_removed().size() != 0 ||
1175       diff_tu_->function_diffs().size() != 0 ||
1176       diff_tu_->global_var_diffs().size() != 0 ||
1177       diff_tu_->enum_type_diffs().size() != 0 ||
1178       diff_tu_->record_type_diffs().size() != 0) {
1179     return CompatibilityStatusIR::Incompatible;
1180   }
1181 
1182   CompatibilityStatusIR combined_status = CompatibilityStatusIR::Compatible;
1183 
1184   if (diff_tu_->enum_type_extension_diffs().size() != 0 ||
1185       diff_tu_->functions_added().size() != 0 ||
1186       diff_tu_->global_vars_added().size() != 0) {
1187     combined_status = combined_status | CompatibilityStatusIR::Extension;
1188   }
1189 
1190   if (diff_tu_->unreferenced_enum_type_diffs().size() != 0 ||
1191       diff_tu_->unreferenced_enum_types_removed().size() != 0 ||
1192       diff_tu_->unreferenced_record_types_removed().size() != 0 ||
1193       diff_tu_->unreferenced_record_type_diffs().size() != 0 ||
1194       diff_tu_->unreferenced_enum_type_extension_diffs().size() != 0 ||
1195       diff_tu_->unreferenced_record_types_added().size() != 0 ||
1196       diff_tu_->unreferenced_enum_types_added().size()) {
1197     combined_status =
1198         combined_status | CompatibilityStatusIR::UnreferencedChanges;
1199   }
1200 
1201   if(diff_tu_->removed_elf_functions().size() != 0 ||
1202      diff_tu_->removed_elf_objects().size() != 0) {
1203     combined_status = combined_status | CompatibilityStatusIR::ElfIncompatible;
1204   }
1205 
1206   return combined_status;
1207 }
1208 
AddCompatibilityStatusIR(CompatibilityStatusIR status)1209 void ProtobufIRDiffDumper::AddCompatibilityStatusIR(
1210     CompatibilityStatusIR status) {
1211   diff_tu_->set_compatibility_status(CompatibilityStatusIRToProtobuf(status));
1212 }
1213 
AddDiffMessageIR(const DiffMessageIR * message,const std::string & type_stack,DiffKind diff_kind)1214 bool ProtobufIRDiffDumper::AddDiffMessageIR(
1215     const DiffMessageIR *message,
1216     const std::string &type_stack,
1217     DiffKind diff_kind) {
1218   switch (message->Kind()) {
1219     case RecordTypeKind:
1220       return AddRecordTypeDiffIR(
1221           static_cast<const RecordTypeDiffIR *>(message),
1222           type_stack, diff_kind);
1223     case EnumTypeKind:
1224       return AddEnumTypeDiffIR(
1225           static_cast<const EnumTypeDiffIR *>(message),
1226           type_stack, diff_kind);
1227     case GlobalVarKind:
1228       return AddGlobalVarDiffIR(
1229           static_cast<const GlobalVarDiffIR*>(message),
1230           type_stack, diff_kind);
1231     case FunctionKind:
1232       return AddFunctionDiffIR(
1233           static_cast<const FunctionDiffIR*>(message),
1234           type_stack, diff_kind);
1235     default:
1236       break;
1237   }
1238   llvm::errs() << "Dump Diff attempted on something not a user defined type" <<
1239                    "/ function / global variable\n";
1240   return false;
1241 }
1242 
AddLinkableMessageIR(const LinkableMessageIR * message,DiffKind diff_kind)1243 bool ProtobufIRDiffDumper::AddLinkableMessageIR(
1244     const LinkableMessageIR *message,
1245     DiffKind diff_kind) {
1246   switch (message->GetKind()) {
1247     case RecordTypeKind:
1248       return AddLoneRecordTypeDiffIR(
1249           static_cast<const RecordTypeIR *>(message), diff_kind);
1250     case EnumTypeKind:
1251       return AddLoneEnumTypeDiffIR(
1252           static_cast<const EnumTypeIR *>(message), diff_kind);
1253     case GlobalVarKind:
1254       return AddLoneGlobalVarDiffIR(
1255           static_cast<const GlobalVarIR*>(message), diff_kind);
1256     case FunctionKind:
1257       return AddLoneFunctionDiffIR(
1258           static_cast<const FunctionIR*>(message), diff_kind);
1259     default:
1260       break;
1261   }
1262   llvm::errs() << "Dump Diff attempted on something not a user defined type" <<
1263                    "/ function / global variable\n";
1264   return false;
1265 }
1266 
AddElfSymbolMessageIR(const ElfSymbolIR * elf_symbol,DiffKind diff_kind)1267 bool ProtobufIRDiffDumper::AddElfSymbolMessageIR (const ElfSymbolIR *elf_symbol,
1268                                                   DiffKind diff_kind) {
1269   switch (elf_symbol->GetKind()) {
1270     case ElfSymbolIR::ElfFunctionKind:
1271       return AddElfFunctionIR(static_cast<const ElfFunctionIR *>(elf_symbol),
1272                               diff_kind);
1273       break;
1274     case ElfSymbolIR::ElfObjectKind:
1275       return AddElfObjectIR(static_cast<const ElfObjectIR *>(elf_symbol),
1276                             diff_kind);
1277       break;
1278   }
1279   // Any other kind is invalid
1280   return false;
1281 }
1282 
AddElfFunctionIR(const ElfFunctionIR * elf_function_ir,DiffKind diff_kind)1283 bool ProtobufIRDiffDumper::AddElfFunctionIR(
1284     const ElfFunctionIR *elf_function_ir, DiffKind diff_kind) {
1285   abi_dump::ElfFunction *added_elf_function = nullptr;
1286   switch(diff_kind) {
1287     case DiffKind::Removed:
1288       added_elf_function = diff_tu_->add_removed_elf_functions();
1289       break;
1290     case DiffKind::Added:
1291       added_elf_function = diff_tu_->add_added_elf_functions();
1292       break;
1293     default:
1294       llvm::errs() << "Invalid call to AddElfFunctionIR\n";
1295       return false;
1296   }
1297   if (added_elf_function == nullptr) {
1298     return false;
1299   }
1300   *added_elf_function =
1301       IRToProtobufConverter::ConvertElfFunctionIR(elf_function_ir);
1302   return true;
1303 }
1304 
AddElfObjectIR(const ElfObjectIR * elf_object_ir,DiffKind diff_kind)1305 bool ProtobufIRDiffDumper::AddElfObjectIR(
1306     const ElfObjectIR *elf_object_ir, DiffKind diff_kind) {
1307   abi_dump::ElfObject *added_elf_object = nullptr;
1308   switch(diff_kind) {
1309     case DiffKind::Removed:
1310       added_elf_object = diff_tu_->add_removed_elf_objects();
1311       break;
1312     case DiffKind::Added:
1313       added_elf_object = diff_tu_->add_added_elf_objects();
1314       break;
1315     default:
1316       llvm::errs() << "Invalid call to AddElfObjectIR\n";
1317       return false;
1318   }
1319   if (added_elf_object == nullptr) {
1320     return false;
1321   }
1322   *added_elf_object =
1323       IRToProtobufConverter::ConvertElfObjectIR(elf_object_ir);
1324   return true;
1325 }
1326 
AddLoneRecordTypeDiffIR(const RecordTypeIR * record_type_ir,DiffKind diff_kind)1327 bool ProtobufIRDiffDumper::AddLoneRecordTypeDiffIR(
1328     const RecordTypeIR *record_type_ir,
1329     DiffKind diff_kind) {
1330   abi_dump::RecordType *added_record_type = nullptr;
1331   switch (diff_kind) {
1332     case DiffKind::Removed:
1333       // Referenced record types do not get reported as added / removed,
1334       // the diff shows up in the parent type / function/ global variable
1335       // referencing the record.
1336       added_record_type = diff_tu_->add_unreferenced_record_types_removed();
1337       break;
1338     case DiffKind::Added:
1339       added_record_type = diff_tu_->add_unreferenced_record_types_added();
1340       break;
1341     default:
1342       llvm::errs() << "Invalid call to AddLoneRecordTypeDiffIR\n";
1343       return false;
1344   }
1345   if (added_record_type == nullptr) {
1346     return false;
1347   }
1348   *added_record_type =
1349       IRToProtobufConverter::ConvertRecordTypeIR(record_type_ir);
1350   return true;
1351 }
1352 
AddLoneFunctionDiffIR(const FunctionIR * function_ir,DiffKind diff_kind)1353 bool ProtobufIRDiffDumper::AddLoneFunctionDiffIR(
1354     const FunctionIR *function_ir,
1355     DiffKind diff_kind) {
1356   abi_dump::FunctionDecl *added_function = nullptr;
1357   switch (diff_kind) {
1358     case DiffKind::Removed:
1359       added_function = diff_tu_->add_functions_removed();
1360       break;
1361     case DiffKind::Added:
1362       added_function = diff_tu_->add_functions_added();
1363       break;
1364     default:
1365       llvm::errs() << "Invalid call to AddLoneFunctionDiffIR\n";
1366       return false;
1367   }
1368   *added_function = IRToProtobufConverter::ConvertFunctionIR(function_ir);
1369   return true;
1370 }
1371 
AddLoneEnumTypeDiffIR(const EnumTypeIR * enum_type_ir,DiffKind diff_kind)1372 bool ProtobufIRDiffDumper::AddLoneEnumTypeDiffIR(
1373     const EnumTypeIR *enum_type_ir, DiffKind diff_kind) {
1374   abi_dump::EnumType *added_enum_type = nullptr;
1375   switch (diff_kind) {
1376     case DiffKind::Removed:
1377       // Referenced enum types do not get reported as added / removed,
1378       // the diff shows up in the parent type / function/ global variable
1379       // referencing the enum.
1380       added_enum_type = diff_tu_->add_unreferenced_enum_types_removed();
1381       break;
1382     case DiffKind::Added:
1383       added_enum_type = diff_tu_->add_unreferenced_enum_types_added();
1384       break;
1385     default:
1386       llvm::errs() << "Invalid call to AddLoneRecordTypeDiffIR\n";
1387       return false;
1388   }
1389   if (added_enum_type == nullptr) {
1390     return false;
1391   }
1392   *added_enum_type = IRToProtobufConverter::ConvertEnumTypeIR(enum_type_ir);
1393   return true;
1394 }
1395 
AddLoneGlobalVarDiffIR(const GlobalVarIR * global_var_ir,DiffKind diff_kind)1396 bool ProtobufIRDiffDumper::AddLoneGlobalVarDiffIR(
1397     const GlobalVarIR *global_var_ir, DiffKind diff_kind) {
1398   abi_dump::GlobalVarDecl *added_global_var = nullptr;
1399   switch (diff_kind) {
1400     case DiffKind::Removed:
1401       added_global_var = diff_tu_->add_global_vars_removed();
1402       break;
1403     case DiffKind::Added:
1404       added_global_var = diff_tu_->add_global_vars_added();
1405       break;
1406     default:
1407       llvm::errs() << "Invalid call to AddLoneFunctionDiffIR\n";
1408       return false;
1409   }
1410   *added_global_var = IRToProtobufConverter::ConvertGlobalVarIR(global_var_ir);
1411   return true;
1412 }
1413 
AddRecordTypeDiffIR(const RecordTypeDiffIR * record_diff_ir,const std::string & type_stack,DiffKind diff_kind)1414 bool ProtobufIRDiffDumper::AddRecordTypeDiffIR(
1415     const RecordTypeDiffIR *record_diff_ir,
1416     const std::string &type_stack,
1417     DiffKind diff_kind) {
1418   abi_diff::RecordTypeDiff *added_record_type_diff = nullptr;
1419   switch (diff_kind) {
1420     case DiffKind::Unreferenced:
1421       added_record_type_diff = diff_tu_->add_unreferenced_record_type_diffs();
1422       break;
1423     case DiffKind::Referenced:
1424       added_record_type_diff = diff_tu_->add_record_type_diffs();
1425       break;
1426     default:
1427       break;
1428   }
1429   if (!added_record_type_diff) {
1430     return false;
1431   }
1432 
1433   *added_record_type_diff =
1434       IRDiffToProtobufConverter::ConvertRecordTypeDiffIR(record_diff_ir);
1435   added_record_type_diff->set_type_stack(type_stack);
1436   return true;
1437 }
1438 
AddFunctionDiffIR(const FunctionDiffIR * function_diff_ir,const std::string & type_stack,DiffKind diff_kind)1439 bool ProtobufIRDiffDumper::AddFunctionDiffIR(
1440     const FunctionDiffIR *function_diff_ir, const std::string &type_stack,
1441     DiffKind diff_kind) {
1442   abi_diff::FunctionDeclDiff *added_function_diff =
1443       diff_tu_->add_function_diffs();
1444   if (!added_function_diff) {
1445     return false;
1446   }
1447   *added_function_diff =
1448       IRDiffToProtobufConverter::ConvertFunctionDiffIR(function_diff_ir);
1449   return true;
1450 }
1451 
AddEnumTypeDiffIR(const EnumTypeDiffIR * enum_diff_ir,const std::string & type_stack,DiffKind diff_kind)1452 bool ProtobufIRDiffDumper::AddEnumTypeDiffIR(const EnumTypeDiffIR *enum_diff_ir,
1453                                              const std::string &type_stack,
1454                                              DiffKind diff_kind) {
1455   abi_diff::EnumTypeDiff *added_enum_type_diff = nullptr;
1456   switch (diff_kind) {
1457     case DiffKind::Unreferenced:
1458       if (enum_diff_ir->IsExtended()) {
1459         added_enum_type_diff =
1460             diff_tu_->add_unreferenced_enum_type_extension_diffs();
1461       } else {
1462         added_enum_type_diff =
1463             diff_tu_->add_unreferenced_enum_type_diffs();
1464       }
1465       break;
1466     case DiffKind::Referenced:
1467       if (enum_diff_ir->IsExtended()) {
1468         added_enum_type_diff =
1469             diff_tu_->add_enum_type_extension_diffs();
1470       } else {
1471         added_enum_type_diff =
1472             diff_tu_->add_enum_type_diffs();
1473       }
1474       break;
1475     default:
1476       break;
1477   }
1478   if (!added_enum_type_diff) {
1479     return false;
1480   }
1481   *added_enum_type_diff =
1482       IRDiffToProtobufConverter::ConvertEnumTypeDiffIR(enum_diff_ir);
1483   added_enum_type_diff->set_type_stack(type_stack);
1484   return true;
1485 }
1486 
AddGlobalVarDiffIR(const GlobalVarDiffIR * global_var_diff_ir,const std::string & type_stack,DiffKind diff_kind)1487 bool ProtobufIRDiffDumper::AddGlobalVarDiffIR(
1488     const GlobalVarDiffIR *global_var_diff_ir,
1489     const std::string &type_stack,
1490     DiffKind diff_kind) {
1491   abi_diff::GlobalVarDeclDiff *added_global_var_diff =
1492       diff_tu_->add_global_var_diffs();
1493   if (!added_global_var_diff) {
1494     return false;
1495   }
1496   *added_global_var_diff =
1497       IRDiffToProtobufConverter::ConvertGlobalVarDiffIR(global_var_diff_ir);
1498   return true;
1499 }
1500 
Dump()1501 bool ProtobufIRDiffDumper::Dump() {
1502   GOOGLE_PROTOBUF_VERIFY_VERSION;
1503   assert(diff_tu_.get() != nullptr);
1504   std::ofstream text_output(dump_path_);
1505   google::protobuf::io::OstreamOutputStream text_os(&text_output);
1506   return google::protobuf::TextFormat::Print(*diff_tu_.get(), &text_os);
1507 }
1508 
1509 } //abi_util
1510