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 !SetIRToProtobufVTableLayout(old_vtable,
59 vtable_layout_diff_ir->GetOldVTable()) ||
60 !SetIRToProtobufVTableLayout(new_vtable,
61 vtable_layout_diff_ir->GetNewVTable())) {
62 return false;
63 }
64 return true;
65 }
66
67 template <typename T>
CopyBaseSpecifiersDiffIRToProtobuf(google::protobuf::RepeatedPtrField<T> * dst,const std::vector<CXXBaseSpecifierIR> & bases_ir)68 static bool CopyBaseSpecifiersDiffIRToProtobuf(
69 google::protobuf::RepeatedPtrField<T> *dst,
70 const std::vector<CXXBaseSpecifierIR> &bases_ir) {
71 for (auto &&base_ir : bases_ir) {
72 T *added_base = dst->Add();
73 if (!SetIRToProtobufBaseSpecifier(added_base, 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 (field == nullptr) {
106 return false;
107 }
108 SetIRToProtobufRecordField(field, record_field_ir);
109 }
110 return true;
111 }
112
AddRecordFieldDiffs(abi_diff::RecordTypeDiff * record_diff_protobuf,const std::vector<RecordFieldDiffIR> & record_field_diffs_ir)113 bool IRDiffToProtobufConverter::AddRecordFieldDiffs(
114 abi_diff::RecordTypeDiff *record_diff_protobuf,
115 const std::vector<RecordFieldDiffIR> &record_field_diffs_ir) {
116 for (auto &&record_field_diff_ir : record_field_diffs_ir) {
117 abi_diff::RecordFieldDeclDiff *record_field_diff =
118 record_diff_protobuf->add_fields_diff();
119 if (record_field_diff == nullptr) {
120 return false;
121 }
122 abi_dump::RecordFieldDecl *old_field =
123 record_field_diff->mutable_old_field();
124 abi_dump::RecordFieldDecl *new_field =
125 record_field_diff->mutable_new_field();
126 if (old_field == nullptr || new_field == nullptr) {
127 return false;
128 }
129 SetIRToProtobufRecordField(old_field,
130 record_field_diff_ir.GetOldField());
131 SetIRToProtobufRecordField(new_field,
132 record_field_diff_ir.GetNewField());
133 }
134 return true;
135 }
136
ConvertRecordTypeDiffIR(const RecordTypeDiffIR * record_type_diff_ir)137 abi_diff::RecordTypeDiff IRDiffToProtobufConverter::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 bool IRDiffToProtobufConverter::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 (!SetIRToProtobufEnumField(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 (!SetIRToProtobufEnumField(field_diff_protobuf->mutable_old_field(),
222 field_diff_ir.GetOldField()) ||
223 !SetIRToProtobufEnumField(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 abi_diff::EnumTypeDiff IRDiffToProtobufConverter::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 abi_diff::GlobalVarDeclDiff IRDiffToProtobufConverter::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 =
266 IRToProtobufConverter::ConvertGlobalVarIR(
267 global_var_diff_ir->GetOldGlobalVar());
268 *new_global_var =
269 IRToProtobufConverter::ConvertGlobalVarIR(
270 global_var_diff_ir->GetNewGlobalVar());
271 return global_var_diff;
272 }
273
ConvertFunctionDiffIR(const FunctionDiffIR * function_diff_ir)274 abi_diff::FunctionDeclDiff IRDiffToProtobufConverter::ConvertFunctionDiffIR(
275 const FunctionDiffIR *function_diff_ir) {
276 abi_diff::FunctionDeclDiff function_diff;
277 function_diff.set_name(function_diff_ir->GetName());
278 abi_dump::FunctionDecl *old_function = function_diff.mutable_old();
279 abi_dump::FunctionDecl *new_function = function_diff.mutable_new_();
280 if (old_function == nullptr || new_function == nullptr) {
281 llvm::errs() << "Function diff could not be added\n";
282 ::exit(1);
283 }
284 *old_function = IRToProtobufConverter::ConvertFunctionIR(
285 function_diff_ir->GetOldFunction());
286 *new_function = IRToProtobufConverter::ConvertFunctionIR(
287 function_diff_ir->GetNewFunction());
288 return function_diff;
289 }
290
291
292 } // namespace repr
293 } // namespace header_checker
294