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_diff_dumper.h"
16
17 #include "repr/ir_diff_representation.h"
18 #include "repr/protobuf/api.h"
19 #include "repr/protobuf/converter.h"
20
21 #include <fstream>
22 #include <memory>
23 #include <string>
24
25 #include <llvm/Support/raw_ostream.h>
26
27 #include <google/protobuf/io/zero_copy_stream_impl.h>
28 #include <google/protobuf/text_format.h>
29
30
31 namespace header_checker {
32 namespace repr {
33
AddTypeInfoDiff(abi_diff::TypeInfoDiff * type_info_diff_protobuf,const TypeDiffIR * type_diff_ir)34 static bool AddTypeInfoDiff(abi_diff::TypeInfoDiff *type_info_diff_protobuf,
35 const TypeDiffIR *type_diff_ir) {
36 abi_diff::TypeInfo *old_type_info_protobuf =
37 type_info_diff_protobuf->mutable_old_type_info();
38 abi_diff::TypeInfo *new_type_info_protobuf =
39 type_info_diff_protobuf->mutable_new_type_info();
40 if (old_type_info_protobuf == nullptr || new_type_info_protobuf == nullptr) {
41 return false;
42 }
43 const std::pair<uint64_t, uint64_t> &sizes = type_diff_ir->GetSizes();
44 const std::pair<uint32_t, uint32_t> &alignments =
45 type_diff_ir->GetAlignments();
46 old_type_info_protobuf->set_size(sizes.first);
47 new_type_info_protobuf->set_size(sizes.second);
48
49 old_type_info_protobuf->set_alignment(alignments.first);
50 new_type_info_protobuf->set_alignment(alignments.second);
51 return true;
52 }
53
AddVTableLayoutDiff(abi_diff::VTableLayoutDiff * vtable_layout_diff_protobuf,const VTableLayoutDiffIR * vtable_layout_diff_ir)54 static bool AddVTableLayoutDiff(
55 abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf,
56 const VTableLayoutDiffIR *vtable_layout_diff_ir) {
57 abi_dump::VTableLayout *old_vtable =
58 vtable_layout_diff_protobuf->mutable_old_vtable();
59 abi_dump::VTableLayout *new_vtable =
60 vtable_layout_diff_protobuf->mutable_new_vtable();
61 if (old_vtable == nullptr || new_vtable == nullptr ||
62 !ConvertVTableLayoutIR(old_vtable,
63 vtable_layout_diff_ir->GetOldVTable()) ||
64 !ConvertVTableLayoutIR(new_vtable,
65 vtable_layout_diff_ir->GetNewVTable())) {
66 return false;
67 }
68 return true;
69 }
70
CopyBaseSpecifiersDiffIRToProtobuf(google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> * dst,const std::vector<CXXBaseSpecifierIR> & bases_ir)71 static bool CopyBaseSpecifiersDiffIRToProtobuf(
72 google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> *dst,
73 const std::vector<CXXBaseSpecifierIR> &bases_ir) {
74 for (auto &&base_ir : bases_ir) {
75 abi_dump::CXXBaseSpecifier *added_base = dst->Add();
76 if (!ConvertCXXBaseSpecifierIR(added_base, base_ir)) {
77 return false;
78 }
79 }
80 return true;
81 }
82
AddBaseSpecifierDiffs(abi_diff::CXXBaseSpecifierDiff * base_specifiers_diff_protobuf,const CXXBaseSpecifierDiffIR * base_specifiers_diff_ir)83 static bool AddBaseSpecifierDiffs(
84 abi_diff::CXXBaseSpecifierDiff *base_specifiers_diff_protobuf,
85 const CXXBaseSpecifierDiffIR *base_specifiers_diff_ir) {
86 if (!CopyBaseSpecifiersDiffIRToProtobuf(
87 base_specifiers_diff_protobuf->mutable_old_bases(),
88 base_specifiers_diff_ir->GetOldBases()) ||
89 !CopyBaseSpecifiersDiffIRToProtobuf(
90 base_specifiers_diff_protobuf->mutable_new_bases(),
91 base_specifiers_diff_ir->GetNewBases())) {
92 return false;
93 }
94 return true;
95 }
96
AddRecordFields(abi_diff::RecordTypeDiff * record_diff_protobuf,const std::vector<const RecordFieldIR * > & record_fields_ir,bool field_removed)97 static bool AddRecordFields(
98 abi_diff::RecordTypeDiff *record_diff_protobuf,
99 const std::vector<const RecordFieldIR *> &record_fields_ir,
100 bool field_removed) {
101 for (auto &&record_field_ir : record_fields_ir) {
102 abi_dump::RecordFieldDecl *field = nullptr;
103 if (field_removed) {
104 field = record_diff_protobuf->add_fields_removed();
105 } else {
106 field = record_diff_protobuf->add_fields_added();
107 }
108 if (!ConvertRecordFieldIR(field, record_field_ir)) {
109 return false;
110 }
111 }
112 return true;
113 }
114
AddRecordFieldDiffs(abi_diff::RecordTypeDiff * record_diff_protobuf,const std::vector<RecordFieldDiffIR> & record_field_diffs_ir)115 static bool AddRecordFieldDiffs(
116 abi_diff::RecordTypeDiff *record_diff_protobuf,
117 const std::vector<RecordFieldDiffIR> &record_field_diffs_ir) {
118 for (auto &&record_field_diff_ir : record_field_diffs_ir) {
119 abi_diff::RecordFieldDeclDiff *record_field_diff =
120 record_diff_protobuf->add_fields_diff();
121 if (record_field_diff == nullptr) {
122 return false;
123 }
124 abi_dump::RecordFieldDecl *old_field =
125 record_field_diff->mutable_old_field();
126 abi_dump::RecordFieldDecl *new_field =
127 record_field_diff->mutable_new_field();
128 if (old_field == nullptr || new_field == nullptr) {
129 return false;
130 }
131 ConvertRecordFieldIR(old_field, record_field_diff_ir.GetOldField());
132 ConvertRecordFieldIR(new_field, record_field_diff_ir.GetNewField());
133 }
134 return true;
135 }
136
ConvertRecordTypeDiffIR(const RecordTypeDiffIR * record_type_diff_ir)137 static abi_diff::RecordTypeDiff ConvertRecordTypeDiffIR(
138 const RecordTypeDiffIR *record_type_diff_ir) {
139 abi_diff::RecordTypeDiff record_type_diff_protobuf;
140 record_type_diff_protobuf.set_name(record_type_diff_ir->GetName());
141 record_type_diff_protobuf.set_linker_set_key(
142 record_type_diff_ir->GetLinkerSetKey());
143 // If a type_info diff exists
144 const TypeDiffIR *type_diff_ir = record_type_diff_ir->GetTypeDiff();
145 if (type_diff_ir != nullptr) {
146 abi_diff::TypeInfoDiff *type_info_diff =
147 record_type_diff_protobuf.mutable_type_info_diff();
148 if (!AddTypeInfoDiff(type_info_diff, type_diff_ir)) {
149 llvm::errs() << "RecordType could not be converted\n";
150 ::exit(1);
151 }
152 }
153 // If vtables differ.
154 const VTableLayoutDiffIR *vtable_layout_diff_ir =
155 record_type_diff_ir->GetVTableLayoutDiff();
156 if (vtable_layout_diff_ir != nullptr) {
157 abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf =
158 record_type_diff_protobuf.mutable_vtable_layout_diff();
159 if (!AddVTableLayoutDiff(vtable_layout_diff_protobuf,
160 vtable_layout_diff_ir)) {
161 llvm::errs() << "VTable layout diff could not be added\n";
162 ::exit(1);
163 }
164 }
165 // If base specifiers differ.
166 const CXXBaseSpecifierDiffIR *base_specifier_diff_ir =
167 record_type_diff_ir->GetBaseSpecifiers();
168 if (base_specifier_diff_ir != nullptr) {
169 abi_diff::CXXBaseSpecifierDiff *base_specifier_diff_protobuf =
170 record_type_diff_protobuf.mutable_bases_diff();
171 if (!AddBaseSpecifierDiffs(base_specifier_diff_protobuf,
172 base_specifier_diff_ir)) {
173 llvm::errs() << "Base Specifier diff could not be added\n";
174 ::exit(1);
175 }
176 }
177 // Field diffs
178 if (!AddRecordFields(&record_type_diff_protobuf,
179 record_type_diff_ir->GetFieldsRemoved(), true) ||
180 !AddRecordFields(&record_type_diff_protobuf,
181 record_type_diff_ir->GetFieldsAdded(), false) ||
182 !AddRecordFieldDiffs(&record_type_diff_protobuf,
183 record_type_diff_ir->GetFieldDiffs())) {
184 llvm::errs() << "Record Field diff could not be added\n";
185 ::exit(1);
186 }
187 return record_type_diff_protobuf;
188 }
189
AddEnumUnderlyingTypeDiff(abi_diff::UnderlyingTypeDiff * underlying_type_diff_protobuf,const std::pair<std::string,std::string> * underlying_type_diff_ir)190 static bool AddEnumUnderlyingTypeDiff(
191 abi_diff::UnderlyingTypeDiff *underlying_type_diff_protobuf,
192 const std::pair<std::string, std::string> *underlying_type_diff_ir) {
193 if (underlying_type_diff_protobuf == nullptr) {
194 return false;
195 }
196 underlying_type_diff_protobuf->set_old_type(underlying_type_diff_ir->first);
197 underlying_type_diff_protobuf->set_new_type(underlying_type_diff_ir->second);
198 return true;
199 }
200
AddEnumFields(google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> * dst,const std::vector<const EnumFieldIR * > & enum_fields)201 static bool AddEnumFields(
202 google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> *dst,
203 const std::vector<const EnumFieldIR *> &enum_fields) {
204 for (auto &&enum_field : enum_fields) {
205 abi_dump::EnumFieldDecl *added_enum_field = dst->Add();
206 if (!ConvertEnumFieldIR(added_enum_field, enum_field)) {
207 return false;
208 }
209 }
210 return true;
211 }
212
AddEnumFieldDiffs(google::protobuf::RepeatedPtrField<abi_diff::EnumFieldDeclDiff> * dst,const std::vector<EnumFieldDiffIR> & fields_diff_ir)213 static bool AddEnumFieldDiffs(
214 google::protobuf::RepeatedPtrField<abi_diff::EnumFieldDeclDiff> *dst,
215 const std::vector<EnumFieldDiffIR> &fields_diff_ir) {
216 for (auto &&field_diff_ir : fields_diff_ir) {
217 abi_diff::EnumFieldDeclDiff *field_diff_protobuf = dst->Add();
218 if (field_diff_protobuf == nullptr) {
219 return false;
220 }
221 if (!ConvertEnumFieldIR(field_diff_protobuf->mutable_old_field(),
222 field_diff_ir.GetOldField()) ||
223 !ConvertEnumFieldIR(field_diff_protobuf->mutable_new_field(),
224 field_diff_ir.GetNewField())) {
225 return false;
226 }
227 }
228 return true;
229 }
230
ConvertEnumTypeDiffIR(const EnumTypeDiffIR * enum_type_diff_ir)231 static abi_diff::EnumTypeDiff ConvertEnumTypeDiffIR(
232 const EnumTypeDiffIR *enum_type_diff_ir) {
233 abi_diff::EnumTypeDiff enum_type_diff_protobuf;
234 enum_type_diff_protobuf.set_name(enum_type_diff_ir->GetName());
235 enum_type_diff_protobuf.set_linker_set_key(
236 enum_type_diff_ir->GetLinkerSetKey());
237 const std::pair<std::string, std::string> *underlying_type_diff =
238 enum_type_diff_ir->GetUnderlyingTypeDiff();
239 if ((underlying_type_diff != nullptr &&
240 !AddEnumUnderlyingTypeDiff(
241 enum_type_diff_protobuf.mutable_underlying_type_diff(),
242 underlying_type_diff)) ||
243 !AddEnumFields(enum_type_diff_protobuf.mutable_fields_removed(),
244 enum_type_diff_ir->GetFieldsRemoved()) ||
245 !AddEnumFields(enum_type_diff_protobuf.mutable_fields_added(),
246 enum_type_diff_ir->GetFieldsAdded()) ||
247 !AddEnumFieldDiffs(enum_type_diff_protobuf.mutable_fields_diff(),
248 enum_type_diff_ir->GetFieldsDiff())) {
249 llvm::errs() << "Enum field diff could not be added\n";
250 ::exit(1);
251 }
252 return enum_type_diff_protobuf;
253 }
254
ConvertGlobalVarDiffIR(const GlobalVarDiffIR * global_var_diff_ir)255 static abi_diff::GlobalVarDeclDiff ConvertGlobalVarDiffIR(
256 const GlobalVarDiffIR *global_var_diff_ir) {
257 abi_diff::GlobalVarDeclDiff global_var_diff;
258 global_var_diff.set_name(global_var_diff_ir->GetName());
259 abi_dump::GlobalVarDecl *old_global_var = global_var_diff.mutable_old();
260 abi_dump::GlobalVarDecl *new_global_var = global_var_diff.mutable_new_();
261 if (old_global_var == nullptr || new_global_var == nullptr) {
262 llvm::errs() << "Globar Var diff could not be added\n";
263 ::exit(1);
264 }
265 *old_global_var = ConvertGlobalVarIR(global_var_diff_ir->GetOldGlobalVar());
266 *new_global_var = ConvertGlobalVarIR(global_var_diff_ir->GetNewGlobalVar());
267 return global_var_diff;
268 }
269
ConvertFunctionDiffIR(const FunctionDiffIR * function_diff_ir)270 static abi_diff::FunctionDeclDiff ConvertFunctionDiffIR(
271 const FunctionDiffIR *function_diff_ir) {
272 abi_diff::FunctionDeclDiff function_diff;
273 function_diff.set_name(function_diff_ir->GetName());
274 abi_dump::FunctionDecl *old_function = function_diff.mutable_old();
275 abi_dump::FunctionDecl *new_function = function_diff.mutable_new_();
276 if (old_function == nullptr || new_function == nullptr) {
277 llvm::errs() << "Function diff could not be added\n";
278 ::exit(1);
279 }
280 *old_function = ConvertFunctionIR(function_diff_ir->GetOldFunction());
281 *new_function = ConvertFunctionIR(function_diff_ir->GetNewFunction());
282 return function_diff;
283 }
284
AddLibNameIR(const std::string & name)285 void ProtobufIRDiffDumper::AddLibNameIR(const std::string &name) {
286 diff_tu_->set_lib_name(name);
287 }
288
AddArchIR(const std::string & arch)289 void ProtobufIRDiffDumper::AddArchIR(const std::string &arch) {
290 diff_tu_->set_arch(arch);
291 }
292
GetCompatibilityStatusIR()293 CompatibilityStatusIR ProtobufIRDiffDumper::GetCompatibilityStatusIR() {
294 if (diff_tu_->functions_removed().size() != 0 ||
295 diff_tu_->global_vars_removed().size() != 0 ||
296 diff_tu_->function_diffs().size() != 0 ||
297 diff_tu_->global_var_diffs().size() != 0 ||
298 diff_tu_->enum_type_diffs().size() != 0 ||
299 diff_tu_->record_type_diffs().size() != 0) {
300 return CompatibilityStatusIR::Incompatible;
301 }
302
303 CompatibilityStatusIR combined_status = CompatibilityStatusIR::Compatible;
304
305 if (diff_tu_->enum_type_extension_diffs().size() != 0 ||
306 diff_tu_->functions_added().size() != 0 ||
307 diff_tu_->global_vars_added().size() != 0 ||
308 diff_tu_->record_type_extension_diffs().size() != 0 ||
309 diff_tu_->function_extension_diffs().size() != 0) {
310 combined_status = combined_status | CompatibilityStatusIR::Extension;
311 }
312
313 if (diff_tu_->unreferenced_enum_type_diffs().size() != 0 ||
314 diff_tu_->unreferenced_enum_type_extension_diffs().size() != 0 ||
315 diff_tu_->unreferenced_enum_types_added().size() != 0 ||
316 diff_tu_->unreferenced_enum_types_removed().size() != 0 ||
317 diff_tu_->unreferenced_record_type_diffs().size() != 0 ||
318 diff_tu_->unreferenced_record_type_extension_diffs().size() != 0 ||
319 diff_tu_->unreferenced_record_types_added().size() != 0 ||
320 diff_tu_->unreferenced_record_types_removed().size() != 0) {
321 combined_status =
322 combined_status | CompatibilityStatusIR::UnreferencedChanges;
323 }
324
325 if (diff_tu_->removed_elf_functions().size() != 0 ||
326 diff_tu_->removed_elf_objects().size() != 0) {
327 combined_status = combined_status | CompatibilityStatusIR::ElfIncompatible;
328 }
329
330 if (diff_tu_->added_elf_functions().size() != 0 ||
331 diff_tu_->added_elf_objects().size() != 0) {
332 combined_status = combined_status | CompatibilityStatusIR::ElfExtension;
333 }
334
335 return combined_status;
336 }
337
AddCompatibilityStatusIR(CompatibilityStatusIR status)338 void ProtobufIRDiffDumper::AddCompatibilityStatusIR(
339 CompatibilityStatusIR status) {
340 diff_tu_->set_compatibility_status(CompatibilityStatusIRToProtobuf(status));
341 }
342
AddDiffMessageIR(const DiffMessageIR * message,const std::string & type_stack,DiffKind diff_kind)343 bool ProtobufIRDiffDumper::AddDiffMessageIR(const DiffMessageIR *message,
344 const std::string &type_stack,
345 DiffKind diff_kind) {
346 switch (message->Kind()) {
347 case RecordTypeKind:
348 return AddRecordTypeDiffIR(
349 static_cast<const RecordTypeDiffIR *>(message), type_stack,
350 diff_kind);
351 case EnumTypeKind:
352 return AddEnumTypeDiffIR(
353 static_cast<const EnumTypeDiffIR *>(message), type_stack, diff_kind);
354 case GlobalVarKind:
355 return AddGlobalVarDiffIR(
356 static_cast<const GlobalVarDiffIR*>(message), type_stack, diff_kind);
357 case FunctionKind:
358 return AddFunctionDiffIR(
359 static_cast<const FunctionDiffIR*>(message), type_stack, diff_kind);
360 default:
361 break;
362 }
363 llvm::errs() << "Dump Diff attempted on something not a user defined type / "
364 << "function / global variable\n";
365 return false;
366 }
367
AddLinkableMessageIR(const LinkableMessageIR * message,DiffKind diff_kind)368 bool ProtobufIRDiffDumper::AddLinkableMessageIR(
369 const LinkableMessageIR *message, DiffKind diff_kind) {
370 switch (message->GetKind()) {
371 case RecordTypeKind:
372 return AddLoneRecordTypeDiffIR(
373 static_cast<const RecordTypeIR *>(message), diff_kind);
374 case EnumTypeKind:
375 return AddLoneEnumTypeDiffIR(
376 static_cast<const EnumTypeIR *>(message), diff_kind);
377 case GlobalVarKind:
378 return AddLoneGlobalVarDiffIR(
379 static_cast<const GlobalVarIR*>(message), diff_kind);
380 case FunctionKind:
381 return AddLoneFunctionDiffIR(
382 static_cast<const FunctionIR*>(message), diff_kind);
383 default:
384 break;
385 }
386 llvm::errs() << "Dump Diff attempted on something not a user defined type / "
387 << "function / global variable\n";
388 return false;
389 }
390
AddElfSymbolMessageIR(const ElfSymbolIR * elf_symbol,DiffKind diff_kind)391 bool ProtobufIRDiffDumper::AddElfSymbolMessageIR(const ElfSymbolIR *elf_symbol,
392 DiffKind diff_kind) {
393 switch (elf_symbol->GetKind()) {
394 case ElfSymbolIR::ElfFunctionKind:
395 return AddElfFunctionIR(static_cast<const ElfFunctionIR *>(elf_symbol),
396 diff_kind);
397 break;
398 case ElfSymbolIR::ElfObjectKind:
399 return AddElfObjectIR(static_cast<const ElfObjectIR *>(elf_symbol),
400 diff_kind);
401 break;
402 }
403 // Any other kind is invalid
404 return false;
405 }
406
AddElfFunctionIR(const ElfFunctionIR * elf_function_ir,DiffKind diff_kind)407 bool ProtobufIRDiffDumper::AddElfFunctionIR(
408 const ElfFunctionIR *elf_function_ir, DiffKind diff_kind) {
409 abi_dump::ElfFunction *added_elf_function = nullptr;
410 switch (diff_kind) {
411 case DiffKind::Removed:
412 added_elf_function = diff_tu_->add_removed_elf_functions();
413 break;
414 case DiffKind::Added:
415 added_elf_function = diff_tu_->add_added_elf_functions();
416 break;
417 default:
418 llvm::errs() << "Invalid call to AddElfFunctionIR\n";
419 return false;
420 }
421 if (added_elf_function == nullptr) {
422 return false;
423 }
424 *added_elf_function = ConvertElfFunctionIR(elf_function_ir);
425 return true;
426 }
427
AddElfObjectIR(const ElfObjectIR * elf_object_ir,DiffKind diff_kind)428 bool ProtobufIRDiffDumper::AddElfObjectIR(
429 const ElfObjectIR *elf_object_ir, DiffKind diff_kind) {
430 abi_dump::ElfObject *added_elf_object = nullptr;
431 switch (diff_kind) {
432 case DiffKind::Removed:
433 added_elf_object = diff_tu_->add_removed_elf_objects();
434 break;
435 case DiffKind::Added:
436 added_elf_object = diff_tu_->add_added_elf_objects();
437 break;
438 default:
439 llvm::errs() << "Invalid call to AddElfObjectIR\n";
440 return false;
441 }
442 if (added_elf_object == nullptr) {
443 return false;
444 }
445 *added_elf_object = ConvertElfObjectIR(elf_object_ir);
446 return true;
447 }
448
AddLoneRecordTypeDiffIR(const RecordTypeIR * record_type_ir,DiffKind diff_kind)449 bool ProtobufIRDiffDumper::AddLoneRecordTypeDiffIR(
450 const RecordTypeIR *record_type_ir, DiffKind diff_kind) {
451 abi_dump::RecordType *added_record_type = nullptr;
452 switch (diff_kind) {
453 case DiffKind::Removed:
454 // Referenced record types do not get reported as added / removed,
455 // the diff shows up in the parent type / function/ global variable
456 // referencing the record.
457 added_record_type = diff_tu_->add_unreferenced_record_types_removed();
458 break;
459 case DiffKind::Added:
460 added_record_type = diff_tu_->add_unreferenced_record_types_added();
461 break;
462 default:
463 llvm::errs() << "Invalid call to AddLoneRecordTypeDiffIR\n";
464 return false;
465 }
466 if (added_record_type == nullptr) {
467 return false;
468 }
469 *added_record_type = ConvertRecordTypeIR(record_type_ir);
470 return true;
471 }
472
AddLoneFunctionDiffIR(const FunctionIR * function_ir,DiffKind diff_kind)473 bool ProtobufIRDiffDumper::AddLoneFunctionDiffIR(
474 const FunctionIR *function_ir, DiffKind diff_kind) {
475 abi_dump::FunctionDecl *added_function = nullptr;
476 switch (diff_kind) {
477 case DiffKind::Removed:
478 added_function = diff_tu_->add_functions_removed();
479 break;
480 case DiffKind::Added:
481 added_function = diff_tu_->add_functions_added();
482 break;
483 default:
484 llvm::errs() << "Invalid call to AddLoneFunctionDiffIR\n";
485 return false;
486 }
487 *added_function = ConvertFunctionIR(function_ir);
488 return true;
489 }
490
AddLoneEnumTypeDiffIR(const EnumTypeIR * enum_type_ir,DiffKind diff_kind)491 bool ProtobufIRDiffDumper::AddLoneEnumTypeDiffIR(
492 const EnumTypeIR *enum_type_ir, DiffKind diff_kind) {
493 abi_dump::EnumType *added_enum_type = nullptr;
494 switch (diff_kind) {
495 case DiffKind::Removed:
496 // Referenced enum types do not get reported as added / removed,
497 // the diff shows up in the parent type / function/ global variable
498 // referencing the enum.
499 added_enum_type = diff_tu_->add_unreferenced_enum_types_removed();
500 break;
501 case DiffKind::Added:
502 added_enum_type = diff_tu_->add_unreferenced_enum_types_added();
503 break;
504 default:
505 llvm::errs() << "Invalid call to AddLoneRecordTypeDiffIR\n";
506 return false;
507 }
508 if (added_enum_type == nullptr) {
509 return false;
510 }
511 *added_enum_type = ConvertEnumTypeIR(enum_type_ir);
512 return true;
513 }
514
AddLoneGlobalVarDiffIR(const GlobalVarIR * global_var_ir,DiffKind diff_kind)515 bool ProtobufIRDiffDumper::AddLoneGlobalVarDiffIR(
516 const GlobalVarIR *global_var_ir, DiffKind diff_kind) {
517 abi_dump::GlobalVarDecl *added_global_var = nullptr;
518 switch (diff_kind) {
519 case DiffKind::Removed:
520 added_global_var = diff_tu_->add_global_vars_removed();
521 break;
522 case DiffKind::Added:
523 added_global_var = diff_tu_->add_global_vars_added();
524 break;
525 default:
526 llvm::errs() << "Invalid call to AddLoneFunctionDiffIR\n";
527 return false;
528 }
529 *added_global_var = ConvertGlobalVarIR(global_var_ir);
530 return true;
531 }
532
AddRecordTypeDiffIR(const RecordTypeDiffIR * record_diff_ir,const std::string & type_stack,DiffKind diff_kind)533 bool ProtobufIRDiffDumper::AddRecordTypeDiffIR(
534 const RecordTypeDiffIR *record_diff_ir, const std::string &type_stack,
535 DiffKind diff_kind) {
536 abi_diff::RecordTypeDiff *added_record_type_diff = nullptr;
537 bool is_extended = record_diff_ir->IsExtended();
538 switch (diff_kind) {
539 case DiffKind::Unreferenced:
540 if (is_extended) {
541 added_record_type_diff =
542 diff_tu_->add_unreferenced_record_type_extension_diffs();
543 } else {
544 added_record_type_diff = diff_tu_->add_unreferenced_record_type_diffs();
545 }
546 break;
547 case DiffKind::Referenced:
548 if (is_extended) {
549 added_record_type_diff = diff_tu_->add_record_type_extension_diffs();
550 } else {
551 added_record_type_diff = diff_tu_->add_record_type_diffs();
552 }
553 break;
554 default:
555 break;
556 }
557 if (!added_record_type_diff) {
558 return false;
559 }
560
561 *added_record_type_diff = ConvertRecordTypeDiffIR(record_diff_ir);
562 added_record_type_diff->set_type_stack(type_stack);
563 return true;
564 }
565
AddFunctionDiffIR(const FunctionDiffIR * function_diff_ir,const std::string & type_stack,DiffKind diff_kind)566 bool ProtobufIRDiffDumper::AddFunctionDiffIR(
567 const FunctionDiffIR *function_diff_ir, const std::string &type_stack,
568 DiffKind diff_kind) {
569 abi_diff::FunctionDeclDiff *added_function_diff =
570 function_diff_ir->IsExtended() ? diff_tu_->add_function_extension_diffs()
571 : diff_tu_->add_function_diffs();
572 if (!added_function_diff) {
573 return false;
574 }
575 *added_function_diff = ConvertFunctionDiffIR(function_diff_ir);
576 return true;
577 }
578
AddEnumTypeDiffIR(const EnumTypeDiffIR * enum_diff_ir,const std::string & type_stack,DiffKind diff_kind)579 bool ProtobufIRDiffDumper::AddEnumTypeDiffIR(const EnumTypeDiffIR *enum_diff_ir,
580 const std::string &type_stack,
581 DiffKind diff_kind) {
582 abi_diff::EnumTypeDiff *added_enum_type_diff = nullptr;
583 switch (diff_kind) {
584 case DiffKind::Unreferenced:
585 if (enum_diff_ir->IsExtended()) {
586 added_enum_type_diff =
587 diff_tu_->add_unreferenced_enum_type_extension_diffs();
588 } else {
589 added_enum_type_diff =
590 diff_tu_->add_unreferenced_enum_type_diffs();
591 }
592 break;
593 case DiffKind::Referenced:
594 if (enum_diff_ir->IsExtended()) {
595 added_enum_type_diff =
596 diff_tu_->add_enum_type_extension_diffs();
597 } else {
598 added_enum_type_diff =
599 diff_tu_->add_enum_type_diffs();
600 }
601 break;
602 default:
603 break;
604 }
605 if (!added_enum_type_diff) {
606 return false;
607 }
608 *added_enum_type_diff = ConvertEnumTypeDiffIR(enum_diff_ir);
609 added_enum_type_diff->set_type_stack(type_stack);
610 return true;
611 }
612
AddGlobalVarDiffIR(const GlobalVarDiffIR * global_var_diff_ir,const std::string & type_stack,DiffKind diff_kind)613 bool ProtobufIRDiffDumper::AddGlobalVarDiffIR(
614 const GlobalVarDiffIR *global_var_diff_ir, const std::string &type_stack,
615 DiffKind diff_kind) {
616 abi_diff::GlobalVarDeclDiff *added_global_var_diff =
617 diff_tu_->add_global_var_diffs();
618 if (!added_global_var_diff) {
619 return false;
620 }
621 *added_global_var_diff = ConvertGlobalVarDiffIR(global_var_diff_ir);
622 return true;
623 }
624
Dump()625 bool ProtobufIRDiffDumper::Dump() {
626 GOOGLE_PROTOBUF_VERIFY_VERSION;
627 assert(diff_tu_.get() != nullptr);
628 std::ofstream text_output(dump_path_);
629 {
630 google::protobuf::io::OstreamOutputStream text_os(&text_output);
631 if (!google::protobuf::TextFormat::Print(*diff_tu_.get(), &text_os)) {
632 return false;
633 }
634 }
635 return text_output.flush().good();
636 }
637
CreateProtobufIRDiffDumper(const std::string & dump_path)638 std::unique_ptr<IRDiffDumper> CreateProtobufIRDiffDumper(
639 const std::string &dump_path) {
640 return std::make_unique<ProtobufIRDiffDumper>(dump_path);
641 }
642
643
644 } // namespace repr
645 } // namespace header_checker
646