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 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 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> 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 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 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 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 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 const TypeDiffIR *type_diff_ir = record_type_diff_ir->GetTypeDiff(); 142 // If a type_info diff exists 143 if (type_diff_ir != nullptr) { 144 abi_diff::TypeInfoDiff *type_info_diff = 145 record_type_diff_protobuf.mutable_type_info_diff(); 146 if (!AddTypeInfoDiff(type_info_diff, type_diff_ir)) { 147 llvm::errs() << "RecordType could not be converted\n"; 148 ::exit(1); 149 } 150 } 151 // If vtables differ. 152 const VTableLayoutDiffIR *vtable_layout_diff_ir = 153 record_type_diff_ir->GetVTableLayoutDiff(); 154 if (vtable_layout_diff_ir != nullptr) { 155 abi_diff::VTableLayoutDiff *vtable_layout_diff_protobuf = 156 record_type_diff_protobuf.mutable_vtable_layout_diff(); 157 if (!AddVTableLayoutDiff(vtable_layout_diff_protobuf, 158 vtable_layout_diff_ir)) { 159 llvm::errs() << "VTable layout diff could not be added\n"; 160 ::exit(1); 161 } 162 } 163 // If base specifiers differ. 164 const CXXBaseSpecifierDiffIR *base_specifier_diff_ir = 165 record_type_diff_ir->GetBaseSpecifiers(); 166 if (base_specifier_diff_ir != nullptr) { 167 abi_diff::CXXBaseSpecifierDiff *base_specifier_diff_protobuf = 168 record_type_diff_protobuf.mutable_bases_diff(); 169 if (!AddBaseSpecifierDiffs(base_specifier_diff_protobuf, 170 base_specifier_diff_ir)) { 171 llvm::errs() << "Base Specifier diff could not be added\n"; 172 ::exit(1); 173 } 174 } 175 // Field diffs 176 if (!AddRecordFields(&record_type_diff_protobuf, 177 record_type_diff_ir->GetFieldsRemoved(), true) || 178 !AddRecordFields(&record_type_diff_protobuf, 179 record_type_diff_ir->GetFieldsAdded(), false) || 180 !AddRecordFieldDiffs(&record_type_diff_protobuf, 181 record_type_diff_ir->GetFieldDiffs())) { 182 llvm::errs() << "Record Field diff could not be added\n"; 183 ::exit(1); 184 } 185 return record_type_diff_protobuf; 186 } 187 188 bool IRDiffToProtobufConverter::AddEnumUnderlyingTypeDiff( 189 abi_diff::UnderlyingTypeDiff *underlying_type_diff_protobuf, 190 const std::pair<std::string, std::string> *underlying_type_diff_ir) { 191 if (underlying_type_diff_protobuf == nullptr) { 192 return false; 193 } 194 underlying_type_diff_protobuf->set_old_type(underlying_type_diff_ir->first); 195 underlying_type_diff_protobuf->set_new_type(underlying_type_diff_ir->second); 196 return true; 197 } 198 199 static bool AddEnumFields( 200 google::protobuf::RepeatedPtrField<abi_dump::EnumFieldDecl> *dst, 201 const std::vector<const EnumFieldIR *> &enum_fields) { 202 for (auto &&enum_field : enum_fields) { 203 abi_dump::EnumFieldDecl *added_enum_field = dst->Add(); 204 if (!SetIRToProtobufEnumField(added_enum_field, enum_field)) { 205 return false; 206 } 207 } 208 return true; 209 } 210 211 static bool AddEnumFieldDiffs( 212 google::protobuf::RepeatedPtrField<abi_diff::EnumFieldDeclDiff> *dst, 213 const std::vector<EnumFieldDiffIR> &fields_diff_ir) { 214 for (auto &&field_diff_ir : fields_diff_ir) { 215 abi_diff::EnumFieldDeclDiff *field_diff_protobuf = dst->Add(); 216 if (field_diff_protobuf == nullptr) { 217 return false; 218 } 219 if (!SetIRToProtobufEnumField(field_diff_protobuf->mutable_old_field(), 220 field_diff_ir.GetOldField()) || 221 !SetIRToProtobufEnumField(field_diff_protobuf->mutable_new_field(), 222 field_diff_ir.GetNewField())) { 223 return false; 224 } 225 } 226 return true; 227 } 228 229 abi_diff::EnumTypeDiff IRDiffToProtobufConverter::ConvertEnumTypeDiffIR( 230 const EnumTypeDiffIR *enum_type_diff_ir) { 231 abi_diff::EnumTypeDiff enum_type_diff_protobuf; 232 enum_type_diff_protobuf.set_name(enum_type_diff_ir->GetName()); 233 const std::pair<std::string, std::string> *underlying_type_diff = 234 enum_type_diff_ir->GetUnderlyingTypeDiff(); 235 if ((underlying_type_diff != nullptr && 236 !AddEnumUnderlyingTypeDiff( 237 enum_type_diff_protobuf.mutable_underlying_type_diff(), 238 underlying_type_diff)) || 239 !AddEnumFields(enum_type_diff_protobuf.mutable_fields_removed(), 240 enum_type_diff_ir->GetFieldsRemoved()) || 241 !AddEnumFields(enum_type_diff_protobuf.mutable_fields_added(), 242 enum_type_diff_ir->GetFieldsAdded()) || 243 !AddEnumFieldDiffs(enum_type_diff_protobuf.mutable_fields_diff(), 244 enum_type_diff_ir->GetFieldsDiff())) { 245 llvm::errs() << "Enum field diff could not be added\n"; 246 ::exit(1); 247 } 248 return enum_type_diff_protobuf; 249 } 250 251 abi_diff::GlobalVarDeclDiff IRDiffToProtobufConverter::ConvertGlobalVarDiffIR( 252 const GlobalVarDiffIR *global_var_diff_ir) { 253 abi_diff::GlobalVarDeclDiff global_var_diff; 254 global_var_diff.set_name(global_var_diff_ir->GetName()); 255 abi_dump::GlobalVarDecl *old_global_var = global_var_diff.mutable_old(); 256 abi_dump::GlobalVarDecl *new_global_var = global_var_diff.mutable_new_(); 257 if (old_global_var == nullptr || new_global_var == nullptr) { 258 llvm::errs() << "Globar Var diff could not be added\n"; 259 ::exit(1); 260 } 261 *old_global_var = 262 IRToProtobufConverter::ConvertGlobalVarIR( 263 global_var_diff_ir->GetOldGlobalVar()); 264 *new_global_var = 265 IRToProtobufConverter::ConvertGlobalVarIR( 266 global_var_diff_ir->GetNewGlobalVar()); 267 return global_var_diff; 268 } 269 270 abi_diff::FunctionDeclDiff IRDiffToProtobufConverter::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 = IRToProtobufConverter::ConvertFunctionIR( 281 function_diff_ir->GetOldFunction()); 282 *new_function = IRToProtobufConverter::ConvertFunctionIR( 283 function_diff_ir->GetNewFunction()); 284 return function_diff; 285 } 286 287 288 } // namespace repr 289 } // namespace header_checker 290