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 #ifndef HEADER_CHECKER_PROTOBUF_CONVERTER_H_
16 #define HEADER_CHECKER_PROTOBUF_CONVERTER_H_
17 
18 #include "repr/ir_diff_representation.h"
19 #include "repr/ir_representation.h"
20 #include "repr/protobuf/abi_diff.h"
21 #include "repr/protobuf/abi_dump.h"
22 
23 #include <llvm/Support/raw_ostream.h>
24 
25 
26 namespace header_checker {
27 namespace repr {
28 
29 
CompatibilityStatusIRToProtobuf(CompatibilityStatusIR status)30 inline abi_diff::CompatibilityStatus CompatibilityStatusIRToProtobuf(
31     CompatibilityStatusIR status) {
32   switch (status) {
33     case CompatibilityStatusIR::Incompatible:
34       return abi_diff::CompatibilityStatus::INCOMPATIBLE;
35     case CompatibilityStatusIR::Extension:
36       return abi_diff::CompatibilityStatus::EXTENSION;
37     default:
38       break;
39   }
40   return abi_diff::CompatibilityStatus::COMPATIBLE;
41 }
42 
ElfSymbolBindingIRToProtobuf(ElfSymbolIR::ElfSymbolBinding binding)43 inline abi_dump::ElfSymbolBinding ElfSymbolBindingIRToProtobuf(
44     ElfSymbolIR::ElfSymbolBinding binding) {
45   switch (binding) {
46     case ElfSymbolIR::ElfSymbolBinding::Global:
47       return abi_dump::ElfSymbolBinding::Global;
48     case ElfSymbolIR::ElfSymbolBinding::Weak:
49       return abi_dump::ElfSymbolBinding::Weak;
50   }
51   // We skip symbols of all other Bindings
52   // TODO: Add all bindings, don't leave out info
53   assert(0);
54 }
55 
ElfSymbolBindingProtobufToIR(abi_dump::ElfSymbolBinding binding)56 inline ElfSymbolIR::ElfSymbolBinding ElfSymbolBindingProtobufToIR(
57     abi_dump::ElfSymbolBinding binding) {
58   switch (binding) {
59     case abi_dump::ElfSymbolBinding::Global:
60       return ElfSymbolIR::ElfSymbolBinding::Global;
61     case abi_dump::ElfSymbolBinding::Weak:
62       return ElfSymbolIR::ElfSymbolBinding::Weak;
63   }
64   // We skip symbols of all other Bindings
65   assert(0);
66 }
67 
AccessIRToProtobuf(AccessSpecifierIR access)68 inline abi_dump::AccessSpecifier AccessIRToProtobuf(AccessSpecifierIR access) {
69   switch (access) {
70     case AccessSpecifierIR::ProtectedAccess:
71       return abi_dump::AccessSpecifier::protected_access;
72     case AccessSpecifierIR::PrivateAccess:
73       return abi_dump::AccessSpecifier::private_access;
74     default:
75       return abi_dump::AccessSpecifier::public_access;
76   }
77   return abi_dump::AccessSpecifier::public_access;
78 }
79 
AccessProtobufToIR(abi_dump::AccessSpecifier access)80 inline AccessSpecifierIR AccessProtobufToIR(
81     abi_dump::AccessSpecifier access) {
82   switch (access) {
83     case abi_dump::AccessSpecifier::protected_access:
84       return AccessSpecifierIR::ProtectedAccess;
85     case abi_dump::AccessSpecifier::private_access:
86       return AccessSpecifierIR::PrivateAccess;
87     default:
88       return AccessSpecifierIR::PublicAccess;
89   }
90   return AccessSpecifierIR::PublicAccess;
91 }
92 
RecordKindIRToProtobuf(RecordTypeIR::RecordKind kind)93 inline abi_dump::RecordKind RecordKindIRToProtobuf(
94     RecordTypeIR::RecordKind kind) {
95   switch (kind) {
96     case RecordTypeIR::RecordKind::struct_kind:
97       return abi_dump::RecordKind::struct_kind;
98 
99     case RecordTypeIR::RecordKind::class_kind:
100       return abi_dump::RecordKind::class_kind;
101 
102     case RecordTypeIR::RecordKind::union_kind:
103       return abi_dump::RecordKind::union_kind;
104 
105     default:
106       return abi_dump::RecordKind::struct_kind;
107   }
108   // Should not be reached
109   assert(false);
110 }
111 
RecordKindProtobufToIR(abi_dump::RecordKind kind)112 inline RecordTypeIR::RecordKind RecordKindProtobufToIR(
113     abi_dump::RecordKind kind) {
114   switch (kind) {
115     case abi_dump::RecordKind::struct_kind:
116       return RecordTypeIR::struct_kind;
117 
118     case abi_dump::RecordKind::class_kind:
119       return RecordTypeIR::class_kind;
120 
121     case abi_dump::RecordKind::union_kind:
122       return RecordTypeIR::union_kind;
123 
124     default:
125       return RecordTypeIR::struct_kind;
126   }
127   // Should not be reached
128   assert(false);
129 }
130 
VTableComponentKindIRToProtobuf(VTableComponentIR::Kind kind)131 inline abi_dump::VTableComponent::Kind VTableComponentKindIRToProtobuf(
132     VTableComponentIR::Kind kind) {
133   switch (kind) {
134     case VTableComponentIR::Kind::VCallOffset:
135       return abi_dump::VTableComponent_Kind_VCallOffset;
136 
137     case VTableComponentIR::Kind::VBaseOffset:
138       return abi_dump::VTableComponent_Kind_VBaseOffset;
139 
140     case VTableComponentIR::Kind::OffsetToTop:
141       return abi_dump::VTableComponent_Kind_OffsetToTop;
142 
143     case VTableComponentIR::Kind::RTTI:
144       return abi_dump::VTableComponent_Kind_RTTI;
145 
146     case VTableComponentIR::Kind::FunctionPointer:
147       return abi_dump::VTableComponent_Kind_FunctionPointer;
148 
149     case VTableComponentIR::Kind::CompleteDtorPointer:
150       return abi_dump::VTableComponent_Kind_CompleteDtorPointer;
151 
152     case VTableComponentIR::Kind::DeletingDtorPointer:
153       return abi_dump::VTableComponent_Kind_DeletingDtorPointer;
154 
155     default:
156       return abi_dump::VTableComponent_Kind_UnusedFunctionPointer;
157   }
158   // Should not be reached
159   assert(false);
160 }
161 
VTableComponentKindProtobufToIR(abi_dump::VTableComponent_Kind kind)162 inline VTableComponentIR::Kind VTableComponentKindProtobufToIR(
163     abi_dump::VTableComponent_Kind kind) {
164   switch (kind) {
165     case abi_dump::VTableComponent_Kind_VCallOffset:
166       return VTableComponentIR::Kind::VCallOffset;
167 
168     case abi_dump::VTableComponent_Kind_VBaseOffset:
169       return VTableComponentIR::Kind::VBaseOffset;
170 
171     case abi_dump::VTableComponent_Kind_OffsetToTop:
172       return VTableComponentIR::Kind::OffsetToTop;
173 
174     case abi_dump::VTableComponent_Kind_RTTI:
175       return VTableComponentIR::Kind::RTTI;
176 
177     case abi_dump::VTableComponent_Kind_FunctionPointer:
178       return VTableComponentIR::Kind::FunctionPointer;
179 
180     case abi_dump::VTableComponent_Kind_CompleteDtorPointer:
181       return VTableComponentIR::Kind::CompleteDtorPointer;
182 
183     case abi_dump::VTableComponent_Kind_DeletingDtorPointer:
184       return VTableComponentIR::Kind::DeletingDtorPointer;
185 
186     default:
187       return VTableComponentIR::Kind::UnusedFunctionPointer;
188   }
189   // Should not be reached
190   assert(false);
191 }
192 
193 class IRToProtobufConverter {
194  private:
195   static bool AddTemplateInformation(
196       abi_dump::TemplateInfo *ti, const TemplatedArtifactIR *ta);
197 
198   static bool AddTypeInfo(
199       abi_dump::BasicNamedAndTypedDecl *type_info, const TypeIR *typep);
200 
201   static bool AddRecordFields(
202       abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir);
203 
204   static bool AddBaseSpecifiers(
205       abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir);
206 
207   static bool AddVTableLayout(
208       abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir);
209 
210   static bool AddEnumFields(abi_dump::EnumType *enum_protobuf,
211                             const EnumTypeIR *enum_ir);
212 
213  public:
214   static abi_dump::EnumType ConvertEnumTypeIR(const EnumTypeIR *enump);
215 
216   static abi_dump::RecordType ConvertRecordTypeIR(const RecordTypeIR *recordp);
217 
218   static abi_dump::FunctionType ConvertFunctionTypeIR (
219       const FunctionTypeIR *function_typep);
220 
221   template <typename CFunctionLikeMessage>
222   static bool AddFunctionParametersAndSetReturnType(
223       CFunctionLikeMessage *function_like_protobuf,
224       const CFunctionLikeIR *cfunction_like_ir);
225 
226   template <typename CFunctionLikeMessage>
227   static bool AddFunctionParameters(CFunctionLikeMessage *function_protobuf,
228                                     const CFunctionLikeIR *cfunction_like_ir);
229 
230   static abi_dump::FunctionDecl ConvertFunctionIR(const FunctionIR *functionp);
231 
232   static abi_dump::GlobalVarDecl ConvertGlobalVarIR(
233       const GlobalVarIR *global_varp);
234 
235   static abi_dump::PointerType ConvertPointerTypeIR(
236       const PointerTypeIR *pointerp);
237 
238   static abi_dump::QualifiedType ConvertQualifiedTypeIR(
239       const QualifiedTypeIR *qualtypep);
240 
241   static abi_dump::BuiltinType ConvertBuiltinTypeIR(
242       const BuiltinTypeIR *builtin_typep);
243 
244   static abi_dump::ArrayType ConvertArrayTypeIR(
245       const ArrayTypeIR *array_typep);
246 
247   static abi_dump::LvalueReferenceType ConvertLvalueReferenceTypeIR(
248       const LvalueReferenceTypeIR *lvalue_reference_typep);
249 
250   static abi_dump::RvalueReferenceType ConvertRvalueReferenceTypeIR(
251       const RvalueReferenceTypeIR *rvalue_reference_typep);
252 
253   static abi_dump::ElfFunction ConvertElfFunctionIR(
254       const ElfFunctionIR *elf_function_ir);
255 
256   static abi_dump::ElfObject ConvertElfObjectIR(
257       const ElfObjectIR *elf_object_ir);
258 };
259 
260 class IRDiffToProtobufConverter {
261  private:
262   static bool AddTypeInfoDiff(
263       abi_diff::TypeInfoDiff *type_info_diff_protobuf,
264       const TypeDiffIR *type_diff_ir);
265 
266   static bool AddVTableLayoutDiff(
267       abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf,
268       const VTableLayoutDiffIR *vtable_layout_diff_ir);
269 
270   static bool AddBaseSpecifierDiffs(
271       abi_diff::CXXBaseSpecifierDiff *base_specifier_diff_protobuf,
272       const CXXBaseSpecifierDiffIR *base_specifier_diff_ir);
273 
274   static bool AddRecordFields(
275       abi_diff::RecordTypeDiff *record_diff_protobuf,
276       const std::vector<const RecordFieldIR *> &record_fields_removed_ir,
277       bool removed);
278 
279   static bool AddRecordFieldDiffs(
280       abi_diff::RecordTypeDiff *record_diff_protobuf,
281       const std::vector<RecordFieldDiffIR> &record_field_diff_ir);
282 
283   static bool AddEnumUnderlyingTypeDiff(
284       abi_diff::UnderlyingTypeDiff *underlying_type_diff_protobuf,
285       const std::pair<std::string, std::string> *underlying_type_diff_ir);
286 
287  public:
288   static abi_diff::RecordTypeDiff ConvertRecordTypeDiffIR(
289       const RecordTypeDiffIR *record_type_diffp);
290 
291   static abi_diff::EnumTypeDiff ConvertEnumTypeDiffIR(
292       const EnumTypeDiffIR *enum_type_diffp);
293 
294   static abi_diff::FunctionDeclDiff ConvertFunctionDiffIR(
295       const FunctionDiffIR *function_diffp);
296 
297   static abi_diff::GlobalVarDeclDiff ConvertGlobalVarDiffIR(
298       const GlobalVarDiffIR *global_var_diffp);
299 };
300 
SetIRToProtobufRecordField(abi_dump::RecordFieldDecl * record_field_protobuf,const RecordFieldIR * record_field_ir)301 inline void SetIRToProtobufRecordField(
302     abi_dump::RecordFieldDecl *record_field_protobuf,
303     const RecordFieldIR *record_field_ir) {
304   record_field_protobuf->set_field_name(record_field_ir->GetName());
305   record_field_protobuf->set_referenced_type(
306       record_field_ir->GetReferencedType());
307   record_field_protobuf->set_access(
308       AccessIRToProtobuf(record_field_ir->GetAccess()));
309   record_field_protobuf->set_field_offset(record_field_ir->GetOffset());
310 }
311 
SetIRToProtobufBaseSpecifier(abi_dump::CXXBaseSpecifier * base_specifier_protobuf,const CXXBaseSpecifierIR & base_specifier_ir)312 inline bool SetIRToProtobufBaseSpecifier(
313     abi_dump::CXXBaseSpecifier *base_specifier_protobuf,
314     const CXXBaseSpecifierIR &base_specifier_ir) {
315   if (!base_specifier_protobuf) {
316     llvm::errs() << "Protobuf base specifier not valid\n";
317     return false;
318   }
319   base_specifier_protobuf->set_referenced_type(
320       base_specifier_ir.GetReferencedType());
321   base_specifier_protobuf->set_is_virtual(
322       base_specifier_ir.IsVirtual());
323   base_specifier_protobuf->set_access(
324       AccessIRToProtobuf(base_specifier_ir.GetAccess()));
325   return true;
326 }
327 
SetIRToProtobufVTableLayout(abi_dump::VTableLayout * vtable_layout_protobuf,const VTableLayoutIR & vtable_layout_ir)328 inline bool SetIRToProtobufVTableLayout(
329     abi_dump::VTableLayout *vtable_layout_protobuf,
330     const VTableLayoutIR &vtable_layout_ir) {
331   if (vtable_layout_protobuf == nullptr) {
332     llvm::errs() << "vtable layout protobuf not valid\n";
333     return false;
334   }
335   for (auto &&vtable_component_ir : vtable_layout_ir.GetVTableComponents()) {
336     abi_dump::VTableComponent *added_vtable_component =
337         vtable_layout_protobuf->add_vtable_components();
338     if (!added_vtable_component) {
339       llvm::errs() << "Couldn't add vtable component\n";
340       return false;
341     }
342     added_vtable_component->set_kind(
343         VTableComponentKindIRToProtobuf(vtable_component_ir.GetKind()));
344     added_vtable_component->set_component_value(vtable_component_ir.GetValue());
345     added_vtable_component->set_mangled_component_name(
346         vtable_component_ir.GetName());
347     added_vtable_component->set_is_pure(vtable_component_ir.GetIsPure());
348   }
349   return true;
350 }
351 
SetIRToProtobufEnumField(abi_dump::EnumFieldDecl * enum_field_protobuf,const EnumFieldIR * enum_field_ir)352 inline bool SetIRToProtobufEnumField(
353     abi_dump::EnumFieldDecl *enum_field_protobuf,
354     const EnumFieldIR *enum_field_ir) {
355   if (enum_field_protobuf == nullptr) {
356     return true;
357   }
358   enum_field_protobuf->set_name(enum_field_ir->GetName());
359   enum_field_protobuf->set_enum_field_value(enum_field_ir->GetValue());
360   return true;
361 }
362 
363 
364 }  // namespace repr
365 }  // namespace header_checker
366 
367 
368 #endif  // HEADER_CHECKER_PROTOBUF_CONVERTER_H_
369