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/converter.h"
16 
17 #include <llvm/Support/raw_ostream.h>
18 
19 #include <fstream>
20 #include <iostream>
21 #include <memory>
22 #include <string>
23 
24 
25 namespace header_checker {
26 namespace repr {
27 
28 
AddTypeInfoDiff(abi_diff::TypeInfoDiff * type_info_diff_protobuf,const TypeDiffIR * type_diff_ir)29 bool IRDiffToProtobufConverter::AddTypeInfoDiff(
30     abi_diff::TypeInfoDiff *type_info_diff_protobuf,
31     const TypeDiffIR *type_diff_ir) {
32   abi_diff::TypeInfo *old_type_info_protobuf =
33       type_info_diff_protobuf->mutable_old_type_info();
34   abi_diff::TypeInfo *new_type_info_protobuf =
35       type_info_diff_protobuf->mutable_new_type_info();
36   if (old_type_info_protobuf == nullptr || new_type_info_protobuf == nullptr) {
37     return false;
38   }
39   const std::pair<uint64_t, uint64_t> &sizes = type_diff_ir->GetSizes();
40   const std::pair<uint32_t, uint32_t> &alignments =
41       type_diff_ir->GetAlignments();
42   old_type_info_protobuf->set_size(sizes.first);
43   new_type_info_protobuf->set_size(sizes.second);
44 
45   old_type_info_protobuf->set_alignment(alignments.first);
46   new_type_info_protobuf->set_alignment(alignments.second);
47   return true;
48 }
49 
AddVTableLayoutDiff(abi_diff::VTableLayoutDiff * vtable_layout_diff_protobuf,const VTableLayoutDiffIR * vtable_layout_diff_ir)50 bool IRDiffToProtobufConverter::AddVTableLayoutDiff(
51     abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf,
52     const VTableLayoutDiffIR *vtable_layout_diff_ir) {
53   abi_dump:: VTableLayout *old_vtable =
54       vtable_layout_diff_protobuf->mutable_old_vtable();
55   abi_dump:: VTableLayout *new_vtable =
56       vtable_layout_diff_protobuf->mutable_new_vtable();
57   if (old_vtable == nullptr || new_vtable == nullptr ||
58       !IRToProtobufConverter::ConvertVTableLayoutIR(
59           old_vtable, vtable_layout_diff_ir->GetOldVTable()) ||
60       !IRToProtobufConverter::ConvertVTableLayoutIR(
61           new_vtable, vtable_layout_diff_ir->GetNewVTable())) {
62     return false;
63   }
64   return true;
65 }
66 
CopyBaseSpecifiersDiffIRToProtobuf(google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> * dst,const std::vector<CXXBaseSpecifierIR> & bases_ir)67 static bool CopyBaseSpecifiersDiffIRToProtobuf(
68     google::protobuf::RepeatedPtrField<abi_dump::CXXBaseSpecifier> *dst,
69     const std::vector<CXXBaseSpecifierIR> &bases_ir) {
70   for (auto &&base_ir : bases_ir) {
71     abi_dump::CXXBaseSpecifier *added_base = dst->Add();
72     if (!IRToProtobufConverter::ConvertCXXBaseSpecifierIR(added_base,
73                                                           base_ir)) {
74       return false;
75     }
76   }
77   return true;
78 }
79 
AddBaseSpecifierDiffs(abi_diff::CXXBaseSpecifierDiff * base_specifiers_diff_protobuf,const CXXBaseSpecifierDiffIR * base_specifiers_diff_ir)80 bool IRDiffToProtobufConverter::AddBaseSpecifierDiffs(
81     abi_diff::CXXBaseSpecifierDiff *base_specifiers_diff_protobuf,
82     const CXXBaseSpecifierDiffIR *base_specifiers_diff_ir) {
83   if (!CopyBaseSpecifiersDiffIRToProtobuf(
84           base_specifiers_diff_protobuf->mutable_old_bases(),
85           base_specifiers_diff_ir->GetOldBases()) ||
86       !CopyBaseSpecifiersDiffIRToProtobuf(
87           base_specifiers_diff_protobuf->mutable_new_bases(),
88           base_specifiers_diff_ir->GetNewBases())) {
89     return false;
90   }
91   return true;
92 }
93 
AddRecordFields(abi_diff::RecordTypeDiff * record_diff_protobuf,const std::vector<const RecordFieldIR * > & record_fields_ir,bool field_removed)94 bool IRDiffToProtobufConverter::AddRecordFields(
95     abi_diff::RecordTypeDiff *record_diff_protobuf,
96     const std::vector<const RecordFieldIR *> &record_fields_ir,
97     bool field_removed) {
98   for (auto &&record_field_ir : record_fields_ir) {
99     abi_dump::RecordFieldDecl *field = nullptr;
100     if (field_removed) {
101       field = record_diff_protobuf->add_fields_removed();
102     } else {
103       field = record_diff_protobuf->add_fields_added();
104     }
105     if (!IRToProtobufConverter::ConvertRecordFieldIR(field, record_field_ir)) {
106       return false;
107     }
108   }
109   return true;
110 }
111 
AddRecordFieldDiffs(abi_diff::RecordTypeDiff * record_diff_protobuf,const std::vector<RecordFieldDiffIR> & record_field_diffs_ir)112 bool IRDiffToProtobufConverter::AddRecordFieldDiffs(
113     abi_diff::RecordTypeDiff *record_diff_protobuf,
114     const std::vector<RecordFieldDiffIR> &record_field_diffs_ir) {
115   for (auto &&record_field_diff_ir : record_field_diffs_ir) {
116     abi_diff::RecordFieldDeclDiff *record_field_diff =
117         record_diff_protobuf->add_fields_diff();
118     if (record_field_diff == nullptr) {
119       return false;
120     }
121     abi_dump::RecordFieldDecl *old_field =
122         record_field_diff->mutable_old_field();
123     abi_dump::RecordFieldDecl *new_field =
124         record_field_diff->mutable_new_field();
125     if (old_field == nullptr || new_field == nullptr) {
126       return false;
127     }
128     IRToProtobufConverter::ConvertRecordFieldIR(
129         old_field, record_field_diff_ir.GetOldField());
130     IRToProtobufConverter::ConvertRecordFieldIR(
131         new_field, record_field_diff_ir.GetNewField());
132   }
133   return true;
134 }
135 
ConvertRecordTypeDiffIR(const RecordTypeDiffIR * record_type_diff_ir)136 abi_diff::RecordTypeDiff IRDiffToProtobufConverter::ConvertRecordTypeDiffIR(
137     const RecordTypeDiffIR *record_type_diff_ir) {
138   abi_diff::RecordTypeDiff record_type_diff_protobuf;
139   record_type_diff_protobuf.set_name(record_type_diff_ir->GetName());
140   record_type_diff_protobuf.set_linker_set_key(
141       record_type_diff_ir->GetLinkerSetKey());
142   // If a type_info diff exists
143   const TypeDiffIR *type_diff_ir = record_type_diff_ir->GetTypeDiff();
144   if (type_diff_ir != nullptr) {
145     abi_diff::TypeInfoDiff *type_info_diff =
146         record_type_diff_protobuf.mutable_type_info_diff();
147     if (!AddTypeInfoDiff(type_info_diff, type_diff_ir)) {
148       llvm::errs() << "RecordType could not be converted\n";
149       ::exit(1);
150     }
151   }
152   // If vtables differ.
153   const VTableLayoutDiffIR *vtable_layout_diff_ir =
154       record_type_diff_ir->GetVTableLayoutDiff();
155   if (vtable_layout_diff_ir != nullptr) {
156     abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf =
157         record_type_diff_protobuf.mutable_vtable_layout_diff();
158     if (!AddVTableLayoutDiff(vtable_layout_diff_protobuf,
159                              vtable_layout_diff_ir)) {
160       llvm::errs() << "VTable layout diff could not be added\n";
161       ::exit(1);
162     }
163   }
164   // If base specifiers differ.
165   const CXXBaseSpecifierDiffIR *base_specifier_diff_ir =
166       record_type_diff_ir->GetBaseSpecifiers();
167   if (base_specifier_diff_ir != nullptr) {
168     abi_diff::CXXBaseSpecifierDiff *base_specifier_diff_protobuf =
169         record_type_diff_protobuf.mutable_bases_diff();
170     if (!AddBaseSpecifierDiffs(base_specifier_diff_protobuf,
171                                base_specifier_diff_ir)) {
172       llvm::errs() << "Base Specifier diff could not be added\n";
173       ::exit(1);
174     }
175   }
176   // Field diffs
177   if (!AddRecordFields(&record_type_diff_protobuf,
178                        record_type_diff_ir->GetFieldsRemoved(), true) ||
179       !AddRecordFields(&record_type_diff_protobuf,
180                        record_type_diff_ir->GetFieldsAdded(), false) ||
181       !AddRecordFieldDiffs(&record_type_diff_protobuf,
182                            record_type_diff_ir->GetFieldDiffs())) {
183     llvm::errs() << "Record Field diff could not be added\n";
184     ::exit(1);
185   }
186   return record_type_diff_protobuf;
187 }
188 
AddEnumUnderlyingTypeDiff(abi_diff::UnderlyingTypeDiff * underlying_type_diff_protobuf,const std::pair<std::string,std::string> * underlying_type_diff_ir)189 bool IRDiffToProtobufConverter::AddEnumUnderlyingTypeDiff(
190     abi_diff::UnderlyingTypeDiff *underlying_type_diff_protobuf,
191     const std::pair<std::string, std::string> *underlying_type_diff_ir) {
192   if (underlying_type_diff_protobuf == nullptr) {
193     return false;
194   }
195   underlying_type_diff_protobuf->set_old_type(underlying_type_diff_ir->first);
196   underlying_type_diff_protobuf->set_new_type(underlying_type_diff_ir->second);
197   return true;
198 }
199 
AddEnumFields(google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> * dst,const std::vector<const EnumFieldIR * > & enum_fields)200 static bool AddEnumFields(
201     google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> *dst,
202     const std::vector<const EnumFieldIR *> &enum_fields) {
203   for (auto &&enum_field : enum_fields) {
204     abi_dump::EnumFieldDecl *added_enum_field = dst->Add();
205     if (!IRToProtobufConverter::ConvertEnumFieldIR(added_enum_field,
206                                                    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 (!IRToProtobufConverter::ConvertEnumFieldIR(
222             field_diff_protobuf->mutable_old_field(),
223             field_diff_ir.GetOldField()) ||
224         !IRToProtobufConverter::ConvertEnumFieldIR(
225             field_diff_protobuf->mutable_new_field(),
226             field_diff_ir.GetNewField())) {
227       return false;
228     }
229   }
230   return true;
231 }
232 
ConvertEnumTypeDiffIR(const EnumTypeDiffIR * enum_type_diff_ir)233 abi_diff::EnumTypeDiff IRDiffToProtobufConverter::ConvertEnumTypeDiffIR(
234     const EnumTypeDiffIR *enum_type_diff_ir) {
235   abi_diff::EnumTypeDiff enum_type_diff_protobuf;
236   enum_type_diff_protobuf.set_name(enum_type_diff_ir->GetName());
237   enum_type_diff_protobuf.set_linker_set_key(
238       enum_type_diff_ir->GetLinkerSetKey());
239   const std::pair<std::string, std::string> *underlying_type_diff =
240       enum_type_diff_ir->GetUnderlyingTypeDiff();
241   if ((underlying_type_diff != nullptr &&
242        !AddEnumUnderlyingTypeDiff(
243            enum_type_diff_protobuf.mutable_underlying_type_diff(),
244            underlying_type_diff)) ||
245       !AddEnumFields(enum_type_diff_protobuf.mutable_fields_removed(),
246                      enum_type_diff_ir->GetFieldsRemoved()) ||
247       !AddEnumFields(enum_type_diff_protobuf.mutable_fields_added(),
248                      enum_type_diff_ir->GetFieldsAdded()) ||
249       !AddEnumFieldDiffs(enum_type_diff_protobuf.mutable_fields_diff(),
250                          enum_type_diff_ir->GetFieldsDiff())) {
251     llvm::errs() << "Enum field diff could not be added\n";
252     ::exit(1);
253   }
254   return enum_type_diff_protobuf;
255 }
256 
ConvertGlobalVarDiffIR(const GlobalVarDiffIR * global_var_diff_ir)257 abi_diff::GlobalVarDeclDiff IRDiffToProtobufConverter::ConvertGlobalVarDiffIR(
258     const GlobalVarDiffIR *global_var_diff_ir) {
259   abi_diff::GlobalVarDeclDiff global_var_diff;
260   global_var_diff.set_name(global_var_diff_ir->GetName());
261   abi_dump::GlobalVarDecl *old_global_var = global_var_diff.mutable_old();
262   abi_dump::GlobalVarDecl *new_global_var = global_var_diff.mutable_new_();
263   if (old_global_var == nullptr || new_global_var == nullptr) {
264     llvm::errs() << "Globar Var diff could not be added\n";
265     ::exit(1);
266   }
267   *old_global_var =
268       IRToProtobufConverter::ConvertGlobalVarIR(
269           global_var_diff_ir->GetOldGlobalVar());
270   *new_global_var =
271       IRToProtobufConverter::ConvertGlobalVarIR(
272           global_var_diff_ir->GetNewGlobalVar());
273   return global_var_diff;
274 }
275 
ConvertFunctionDiffIR(const FunctionDiffIR * function_diff_ir)276 abi_diff::FunctionDeclDiff IRDiffToProtobufConverter::ConvertFunctionDiffIR(
277     const FunctionDiffIR *function_diff_ir) {
278   abi_diff::FunctionDeclDiff function_diff;
279   function_diff.set_name(function_diff_ir->GetName());
280   abi_dump::FunctionDecl *old_function = function_diff.mutable_old();
281   abi_dump::FunctionDecl *new_function = function_diff.mutable_new_();
282   if (old_function == nullptr || new_function == nullptr) {
283     llvm::errs() << "Function diff could not be added\n";
284     ::exit(1);
285   }
286   *old_function = IRToProtobufConverter::ConvertFunctionIR(
287       function_diff_ir->GetOldFunction());
288   *new_function = IRToProtobufConverter::ConvertFunctionIR(
289       function_diff_ir->GetNewFunction());
290   return function_diff;
291 }
292 
293 
294 }  // namespace repr
295 }  // namespace header_checker
296