1 // Copyright (C) 2016 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 "dumper/abi_wrappers.h"
16
17 #include "repr/ir_reader.h"
18 #include "utils/header_abi_util.h"
19
20 #include <clang/AST/QualTypeNames.h>
21 #include <clang/Index/CodegenNameGenerator.h>
22
23 #include <string>
24
25 #include <assert.h>
26 #include <limits.h>
27 #include <stdlib.h>
28
29
30 namespace header_checker {
31 namespace dumper {
32
33
ABIWrapper(clang::MangleContext * mangle_contextp,clang::ASTContext * ast_contextp,const clang::CompilerInstance * cip,repr::ModuleIR * module,ASTCaches * ast_caches)34 ABIWrapper::ABIWrapper(
35 clang::MangleContext *mangle_contextp,
36 clang::ASTContext *ast_contextp,
37 const clang::CompilerInstance *cip,
38 repr::ModuleIR *module,
39 ASTCaches *ast_caches)
40 : cip_(cip),
41 mangle_contextp_(mangle_contextp),
42 ast_contextp_(ast_contextp),
43 module_(module),
44 ast_caches_(ast_caches) {}
45
GetCachedDeclSourceFile(const clang::Decl * decl,const clang::CompilerInstance * cip)46 std::string ABIWrapper::GetCachedDeclSourceFile(
47 const clang::Decl *decl, const clang::CompilerInstance *cip) {
48 assert(decl != nullptr);
49 auto result = ast_caches_->decl_to_source_file_cache_.find(decl);
50 if (result == ast_caches_->decl_to_source_file_cache_.end()) {
51 return GetDeclSourceFile(decl, cip);
52 }
53 return result->second;
54 }
55
GetTagDecl(clang::QualType qual_type)56 static const clang::TagDecl *GetTagDecl(clang::QualType qual_type) {
57 const clang::Type *type_ptr = qual_type.getCanonicalType().getTypePtr();
58 assert(type_ptr != nullptr);
59 const clang::TagDecl *tag_decl = type_ptr->getAsTagDecl();
60 return tag_decl;
61 }
62
GetAnonymousRecord(clang::QualType type)63 static const clang::RecordDecl *GetAnonymousRecord(clang::QualType type) {
64 const clang::Type *type_ptr = type.getTypePtr();
65 assert(type_ptr != nullptr);
66 if (!type_ptr->isRecordType()) {
67 return nullptr;
68 }
69 const clang::TagDecl *tag_decl = type_ptr->getAsTagDecl();
70 if (!tag_decl) {
71 return nullptr;
72 }
73 const clang::RecordDecl *record_decl =
74 llvm::dyn_cast<clang::RecordDecl>(tag_decl);
75
76 if (record_decl != nullptr &&
77 (!record_decl->hasNameForLinkage() ||
78 record_decl->isAnonymousStructOrUnion())) {
79 return record_decl;
80 }
81 return nullptr;
82 }
83
GetAnonymousEnum(const clang::QualType qual_type)84 static const clang::EnumDecl *GetAnonymousEnum(
85 const clang::QualType qual_type) {
86 const clang::Type *type_ptr = qual_type.getTypePtr();
87 assert(type_ptr != nullptr);
88 const clang::TagDecl *tag_decl = type_ptr->getAsTagDecl();
89 if (!tag_decl) {
90 return nullptr;
91 }
92 const clang::EnumDecl *enum_decl = llvm::dyn_cast<clang::EnumDecl>(tag_decl);
93 if (!enum_decl || enum_decl->hasNameForLinkage()) {
94 return nullptr;
95 }
96 return enum_decl;
97 }
98
IsReferencingType(clang::QualType qual_type)99 static bool IsReferencingType(clang::QualType qual_type) {
100 const clang::QualType canonical_type = qual_type.getCanonicalType();
101 const clang::Type *base_type = canonical_type.getTypePtr();
102 bool is_ptr = base_type->isPointerType();
103 bool is_reference = base_type->isReferenceType();
104 bool is_array = base_type->isArrayType();
105 return is_array || is_ptr || is_reference || qual_type.hasLocalQualifiers();
106 }
107
108 static clang::QualType GetReferencedType(const clang::QualType qual_type);
109
GetFinalReferencedType(clang::QualType qual_type)110 static clang::QualType GetFinalReferencedType(clang::QualType qual_type) {
111 while (IsReferencingType(qual_type)) {
112 qual_type = GetReferencedType(qual_type);
113 }
114 return qual_type;
115 }
116
TypeNameWithFinalDestination(clang::QualType qual_type)117 std::string ABIWrapper::TypeNameWithFinalDestination(clang::QualType qual_type) {
118 clang::QualType canonical_qual_type = qual_type.getCanonicalType();
119 const std::string qual_type_name = QualTypeToString(canonical_qual_type);
120 clang::QualType final_destination_type =
121 GetFinalReferencedType(canonical_qual_type);
122 const clang::RecordDecl *anon_record =
123 GetAnonymousRecord(final_destination_type);
124 if (anon_record) {
125 clang::SourceManager &sm = cip_->getSourceManager();
126 clang::SourceLocation location = anon_record->getLocation();
127 return qual_type_name + " at " + location.printToString(sm);
128 }
129 return qual_type_name;
130 }
131
GetKeyForTypeId(clang::QualType qual_type)132 std::string ABIWrapper::GetKeyForTypeId(clang::QualType qual_type) {
133 clang::QualType canonical_qual_type = qual_type.getCanonicalType();
134 clang::QualType final_destination_type =
135 GetFinalReferencedType(canonical_qual_type);
136 // Get the tag id for final destionation and add that to the type name with
137 // final destination. This helps in avoiding aliasing of types when fully
138 // qualified type-name doesn't expand all template parameters with their
139 // namespaces.
140 return TypeNameWithFinalDestination(qual_type) +
141 GetTypeUniqueId(GetTagDecl(final_destination_type));
142 }
143
GetDeclSourceFile(const clang::Decl * decl,const clang::CompilerInstance * cip)144 std::string ABIWrapper::GetDeclSourceFile(const clang::Decl *decl,
145 const clang::CompilerInstance *cip) {
146 clang::SourceManager &sm = cip->getSourceManager();
147 clang::SourceLocation location = decl->getLocation();
148 // We need to use the expansion location to identify whether we should recurse
149 // into the AST Node or not. For eg: macros specifying LinkageSpecDecl can
150 // have their spelling location defined somewhere outside a source / header
151 // file belonging to a library. This should not allow the AST node to be
152 // skipped. Its expansion location will still be the source-file / header
153 // belonging to the library.
154 clang::SourceLocation expansion_location = sm.getExpansionLoc(location);
155 llvm::StringRef file_name = sm.getFilename(expansion_location);
156 return utils::RealPath(file_name.str());
157 }
158
AccessClangToIR(const clang::AccessSpecifier sp)159 static repr::AccessSpecifierIR AccessClangToIR(
160 const clang::AccessSpecifier sp) {
161 switch (sp) {
162 case clang::AS_private: {
163 return repr::AccessSpecifierIR::PrivateAccess;
164 break;
165 }
166 case clang::AS_protected: {
167 return repr::AccessSpecifierIR::ProtectedAccess;
168 break;
169 }
170 default: {
171 return repr::AccessSpecifierIR::PublicAccess;
172 break;
173 }
174 }
175 }
176
CreateAnonymousRecord(const clang::RecordDecl * record_decl)177 bool ABIWrapper::CreateAnonymousRecord(const clang::RecordDecl *record_decl) {
178 RecordDeclWrapper record_decl_wrapper(mangle_contextp_, ast_contextp_, cip_,
179 record_decl, module_, ast_caches_);
180 return record_decl_wrapper.GetRecordDecl();
181 }
182
183 // Get type 'referenced' by qual_type. Referenced type implies, in order:
184 // 1) Strip off all qualifiers if qual_type has CVR qualifiers.
185 // 2) Strip off a pointer level if qual_type is a pointer.
186 // 3) Strip off the reference if qual_type is a reference.
187 // Note: qual_type is expected to be a canonical type.
GetReferencedType(const clang::QualType qual_type)188 static clang::QualType GetReferencedType(const clang::QualType qual_type) {
189 const clang::Type *type_ptr = qual_type.getTypePtr();
190 if (qual_type.hasLocalQualifiers()) {
191 return qual_type.getLocalUnqualifiedType();
192 }
193 if (type_ptr->isPointerType()) {
194 return type_ptr->getPointeeType();
195 }
196 if (type_ptr->isArrayType()) {
197 return
198 type_ptr->getArrayElementTypeNoTypeQual()->getCanonicalTypeInternal();
199 }
200 return qual_type.getNonReferenceType();
201 }
202
CreateExtendedType(clang::QualType qual_type,repr::TypeIR * typep)203 bool ABIWrapper::CreateExtendedType(clang::QualType qual_type,
204 repr::TypeIR *typep) {
205 const clang::QualType canonical_type = qual_type.getCanonicalType();
206 // The source file is going to be set later anyway.
207 return CreateBasicNamedAndTypedDecl(canonical_type, typep, "");
208 }
209
210 // This overload takes in a qualtype and adds its information to the abi-dump on
211 // its own.
CreateBasicNamedAndTypedDecl(clang::QualType qual_type,const std::string & source_file)212 bool ABIWrapper::CreateBasicNamedAndTypedDecl(clang::QualType qual_type,
213 const std::string &source_file) {
214 const std::string &type_key = GetKeyForTypeId(qual_type);
215 const clang::QualType canonical_type = qual_type.getCanonicalType();
216 const clang::Type *base_type = canonical_type.getTypePtr();
217 bool is_builtin = base_type->isBuiltinType();
218 bool should_continue_with_recursive_type_creation =
219 IsReferencingType(canonical_type) || is_builtin ||
220 base_type->isFunctionType() ||
221 (GetAnonymousRecord(canonical_type) != nullptr);
222 if (!should_continue_with_recursive_type_creation ||
223 !ast_caches_->type_cache_.insert(type_key).second) {
224 return true;
225 }
226 // Do something similar to what is being done right now. Create an object
227 // extending Type and return a pointer to that and pass it to CreateBasic...
228 // CreateBasic...(qualtype, Type *) fills in size, alignemnt etc.
229 auto type_and_status = SetTypeKind(canonical_type, source_file);
230 std::unique_ptr<repr::TypeIR> typep = std::move(type_and_status.typep_);
231 if (!base_type->isVoidType() && type_and_status.should_create_type_ &&
232 !typep) {
233 llvm::errs() << "nullptr with valid type while creating basic type\n";
234 return false;
235 }
236 if (!type_and_status.should_create_type_) {
237 return true;
238 }
239 return (CreateBasicNamedAndTypedDecl(
240 canonical_type, typep.get(), source_file) &&
241 module_->AddLinkableMessage(*typep));
242 }
243
GetMangledRTTI(const clang::CXXRecordDecl * cxx_record_decl)244 std::string RecordDeclWrapper::GetMangledRTTI(
245 const clang::CXXRecordDecl *cxx_record_decl) {
246 clang::QualType qual_type =
247 cxx_record_decl->getTypeForDecl()->getCanonicalTypeInternal();
248 llvm::SmallString<256> uid;
249 llvm::raw_svector_ostream out(uid);
250 mangle_contextp_->mangleCXXRTTI(qual_type, out);
251 return uid.str();
252 }
253
GetTypeUniqueId(const clang::TagDecl * tag_decl)254 std::string ABIWrapper::GetTypeUniqueId(const clang::TagDecl *tag_decl) {
255 if (!tag_decl) {
256 return "";
257 }
258 clang::QualType qual_type =
259 tag_decl->getTypeForDecl()->getCanonicalTypeInternal();
260 if (!tag_decl->isExternCContext() && ast_contextp_->getLangOpts().CPlusPlus) {
261 llvm::SmallString<256> uid;
262 llvm::raw_svector_ostream out(uid);
263 mangle_contextp_->mangleCXXRTTIName(qual_type, out);
264 return uid.str();
265 }
266 return QualTypeToString(qual_type);
267 }
268
269 // CreateBasicNamedAndTypedDecl creates a BasicNamedAndTypedDecl which will
270 // include all the generic information of a basic type. Other methods will
271 // create more specific information, e.g. RecordDecl, EnumDecl.
CreateBasicNamedAndTypedDecl(clang::QualType canonical_type,repr::TypeIR * typep,const std::string & source_file)272 bool ABIWrapper::CreateBasicNamedAndTypedDecl(
273 clang::QualType canonical_type, repr::TypeIR *typep,
274 const std::string &source_file) {
275 // Cannot determine the size and alignment for template parameter dependent
276 // types as well as incomplete types.
277 const clang::Type *base_type = canonical_type.getTypePtr();
278 assert(base_type != nullptr);
279 clang::Type::TypeClass type_class = base_type->getTypeClass();
280 // Temporary hack for auto type sizes. Not determinable.
281 if ((type_class != clang::Type::Auto) && !base_type->isIncompleteType() &&
282 !(base_type->isDependentType())) {
283 std::pair<clang::CharUnits, clang::CharUnits> size_and_alignment =
284 ast_contextp_->getTypeInfoInChars(canonical_type);
285 size_t size = size_and_alignment.first.getQuantity();
286 size_t alignment = size_and_alignment.second.getQuantity();
287 typep->SetSize(size);
288 typep->SetAlignment(alignment);
289 }
290 std::string type_name_with_destination =
291 TypeNameWithFinalDestination(canonical_type);
292 typep->SetName(type_name_with_destination);
293 typep->SetLinkerSetKey(type_name_with_destination);
294 // Default values are false, we don't set them since explicitly doing that
295 // makes the ABI dumps more verbose.
296 // This type has a reference type if its a pointer / reference OR it has CVR
297 // qualifiers.
298 clang::QualType referenced_type = GetReferencedType(canonical_type);
299 typep->SetReferencedType(
300 ast_caches_->GetTypeId(GetKeyForTypeId(referenced_type)));
301 typep->SetSelfType(ast_caches_->GetTypeId(GetKeyForTypeId(canonical_type)));
302 // Create the type for referenced type.
303 return CreateBasicNamedAndTypedDecl(referenced_type, source_file);
304 }
305
GetTypeLinkageName(const clang::Type * typep)306 std::string ABIWrapper::GetTypeLinkageName(const clang::Type *typep) {
307 assert(typep != nullptr);
308 clang::QualType qt = typep->getCanonicalTypeInternal();
309 return QualTypeToString(qt);
310 }
311
312 // This method returns a TypeAndCreationStatus object. This object contains a
313 // type and information to tell the clients of this method whether the caller
314 // should continue creating the type.
SetTypeKind(const clang::QualType canonical_type,const std::string & source_file)315 TypeAndCreationStatus ABIWrapper::SetTypeKind(
316 const clang::QualType canonical_type, const std::string &source_file) {
317 if (canonical_type.hasLocalQualifiers()) {
318 auto qual_type_ir =
319 std::make_unique<repr::QualifiedTypeIR>();
320 qual_type_ir->SetConstness(canonical_type.isConstQualified());
321 qual_type_ir->SetRestrictedness(canonical_type.isRestrictQualified());
322 qual_type_ir->SetVolatility(canonical_type.isVolatileQualified());
323 qual_type_ir->SetSourceFile(source_file);
324 return TypeAndCreationStatus(std::move(qual_type_ir));
325 }
326 const clang::Type *type_ptr = canonical_type.getTypePtr();
327 if (type_ptr->isPointerType()) {
328 auto pointer_type_ir = std::make_unique<repr::PointerTypeIR>();
329 pointer_type_ir->SetSourceFile(source_file);
330 return TypeAndCreationStatus(std::move(pointer_type_ir));
331 }
332 if (type_ptr->isLValueReferenceType()) {
333 auto lvalue_reference_type_ir =
334 std::make_unique<repr::LvalueReferenceTypeIR>();
335 lvalue_reference_type_ir->SetSourceFile(source_file);
336 return TypeAndCreationStatus(std::move(lvalue_reference_type_ir));
337 }
338 if (type_ptr->isRValueReferenceType()) {
339 auto rvalue_reference_type_ir =
340 std::make_unique<repr::RvalueReferenceTypeIR>();
341 rvalue_reference_type_ir->SetSourceFile(source_file);
342 return TypeAndCreationStatus(std::move(rvalue_reference_type_ir));
343 }
344 if (type_ptr->isArrayType()) {
345 auto array_type_ir = std::make_unique<repr::ArrayTypeIR>();
346 array_type_ir->SetSourceFile(source_file);
347 return TypeAndCreationStatus(std::move(array_type_ir));
348 }
349 if (type_ptr->isEnumeralType()) {
350 return TypeAndCreationStatus(std::make_unique<repr::EnumTypeIR>());
351 }
352 if (type_ptr->isBuiltinType()) {
353 auto builtin_type_ir = std::make_unique<repr::BuiltinTypeIR>();
354 builtin_type_ir->SetSignedness(type_ptr->isUnsignedIntegerType());
355 builtin_type_ir->SetIntegralType(type_ptr->isIntegralType(*ast_contextp_));
356 return TypeAndCreationStatus(std::move(builtin_type_ir));
357 }
358 if (auto &&func_type_ptr =
359 llvm::dyn_cast<const clang::FunctionType>(type_ptr)) {
360 FunctionTypeWrapper function_type_wrapper(mangle_contextp_, ast_contextp_,
361 cip_, func_type_ptr, module_,
362 ast_caches_, source_file);
363 if (!function_type_wrapper.GetFunctionType()) {
364 llvm::errs() << "FunctionType could not be created\n";
365 ::exit(1);
366 }
367 }
368 if (type_ptr->isRecordType()) {
369 // If this record is anonymous, create it.
370 const clang::RecordDecl *anon_record = GetAnonymousRecord(canonical_type);
371 // Avoid constructing RecordDeclWrapper with invalid record, which results
372 // in segmentation fault.
373 if (anon_record && !anon_record->isInvalidDecl() &&
374 !CreateAnonymousRecord(anon_record)) {
375 llvm::errs() << "Anonymous record could not be created\n";
376 ::exit(1);
377 }
378 }
379 return TypeAndCreationStatus(nullptr, false);
380 }
381
GetMangledNameDecl(const clang::NamedDecl * decl,clang::MangleContext * mangle_contextp)382 std::string ABIWrapper::GetMangledNameDecl(
383 const clang::NamedDecl *decl, clang::MangleContext *mangle_contextp) {
384 if (!mangle_contextp->shouldMangleDeclName(decl)) {
385 clang::IdentifierInfo *identifier = decl->getIdentifier();
386 return identifier ? identifier->getName() : "";
387 }
388 std::string mangled_name;
389 llvm::raw_string_ostream ostream(mangled_name);
390 mangle_contextp->mangleName(decl, ostream);
391 ostream.flush();
392 return mangled_name;
393 }
394
GetTagDeclQualifiedName(const clang::TagDecl * decl)395 std::string ABIWrapper::GetTagDeclQualifiedName(const clang::TagDecl *decl) {
396 if (decl->getTypedefNameForAnonDecl()) {
397 return decl->getTypedefNameForAnonDecl()->getQualifiedNameAsString();
398 }
399 return decl->getQualifiedNameAsString();
400 }
401
SetupTemplateArguments(const clang::TemplateArgumentList * tl,repr::TemplatedArtifactIR * ta,const std::string & source_file)402 bool ABIWrapper::SetupTemplateArguments(const clang::TemplateArgumentList *tl,
403 repr::TemplatedArtifactIR *ta,
404 const std::string &source_file) {
405 repr::TemplateInfoIR template_info;
406 for (int i = 0; i < tl->size(); i++) {
407 const clang::TemplateArgument &arg = (*tl)[i];
408 // TODO: More comprehensive checking needed.
409 if (arg.getKind() != clang::TemplateArgument::Type) {
410 continue;
411 }
412 clang::QualType type = arg.getAsType();
413 template_info.AddTemplateElement(
414 repr::TemplateElementIR(
415 ast_caches_->GetTypeId(GetKeyForTypeId(type))));
416 if (!CreateBasicNamedAndTypedDecl(type, source_file)) {
417 llvm::errs() << "Setting up template arguments failed\n";
418 return false;
419 }
420 }
421 ta->SetTemplateInfo(std::move(template_info));
422 return true;
423 }
424
QualTypeToString(const clang::QualType & sweet_qt)425 std::string ABIWrapper::QualTypeToString(const clang::QualType &sweet_qt) {
426 const clang::QualType salty_qt = sweet_qt.getCanonicalType();
427 // clang::TypeName::getFullyQualifiedName removes the part of the type related
428 // to it being a template parameter. Don't use it for dependent types.
429 if (salty_qt.getTypePtr()->isDependentType()) {
430 return salty_qt.getAsString();
431 }
432 return clang::TypeName::getFullyQualifiedName(
433 salty_qt, *ast_contextp_, ast_contextp_->getPrintingPolicy());
434 }
435
FunctionTypeWrapper(clang::MangleContext * mangle_contextp,clang::ASTContext * ast_contextp,const clang::CompilerInstance * compiler_instance_p,const clang::FunctionType * function_type,repr::ModuleIR * module,ASTCaches * ast_caches,const std::string & source_file)436 FunctionTypeWrapper::FunctionTypeWrapper(
437 clang::MangleContext *mangle_contextp, clang::ASTContext *ast_contextp,
438 const clang::CompilerInstance *compiler_instance_p,
439 const clang::FunctionType *function_type, repr::ModuleIR *module,
440 ASTCaches *ast_caches, const std::string &source_file)
441 : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p, module,
442 ast_caches),
443 function_type_(function_type),
444 source_file_(source_file) {}
445
SetupFunctionType(repr::FunctionTypeIR * function_type_ir)446 bool FunctionTypeWrapper::SetupFunctionType(
447 repr::FunctionTypeIR *function_type_ir) {
448 // Add ReturnType
449 function_type_ir->SetReturnType(
450 ast_caches_->GetTypeId(GetKeyForTypeId(function_type_->getReturnType())));
451 function_type_ir->SetSourceFile(source_file_);
452 const clang::FunctionProtoType *function_pt =
453 llvm::dyn_cast<clang::FunctionProtoType>(function_type_);
454 if (!function_pt) {
455 return true;
456 }
457 for (unsigned i = 0, e = function_pt->getNumParams(); i != e; ++i) {
458 clang::QualType param_type = function_pt->getParamType(i);
459 if (!SetupFunctionParameter(function_type_ir, param_type, false,
460 source_file_)) {
461 return false;
462 }
463 }
464 return true;
465 }
466
GetFunctionType()467 bool FunctionTypeWrapper::GetFunctionType() {
468 auto abi_decl = std::make_unique<repr::FunctionTypeIR>();
469 clang::QualType canonical_type = function_type_->getCanonicalTypeInternal();
470 if (!CreateBasicNamedAndTypedDecl(canonical_type, abi_decl.get(), "")) {
471 llvm::errs() << "Couldn't create (function type) extended type\n";
472 return false;
473 }
474 return SetupFunctionType(abi_decl.get()) &&
475 module_->AddLinkableMessage(*abi_decl);
476 }
477
FunctionDeclWrapper(clang::MangleContext * mangle_contextp,clang::ASTContext * ast_contextp,const clang::CompilerInstance * compiler_instance_p,const clang::FunctionDecl * decl,repr::ModuleIR * module,ASTCaches * ast_caches)478 FunctionDeclWrapper::FunctionDeclWrapper(
479 clang::MangleContext *mangle_contextp,
480 clang::ASTContext *ast_contextp,
481 const clang::CompilerInstance *compiler_instance_p,
482 const clang::FunctionDecl *decl,
483 repr::ModuleIR *module,
484 ASTCaches *ast_caches)
485 : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p, module,
486 ast_caches),
487 function_decl_(decl) {}
488
SetupThisParameter(repr::FunctionIR * functionp,const std::string & source_file)489 bool FunctionDeclWrapper::SetupThisParameter(repr::FunctionIR *functionp,
490 const std::string &source_file) {
491 const clang::CXXMethodDecl *cxx_method_decl =
492 llvm::dyn_cast<clang::CXXMethodDecl>(function_decl_);
493 // No this pointer for static methods.
494 if (!cxx_method_decl || cxx_method_decl->isStatic()) {
495 return true;
496 }
497 clang::QualType this_type = cxx_method_decl->getThisType();
498 return SetupFunctionParameter(functionp, this_type, false, source_file, true);
499 }
500
SetupFunctionParameter(repr::CFunctionLikeIR * functionp,const clang::QualType qual_type,bool has_default_arg,const std::string & source_file,bool is_this_ptr)501 bool ABIWrapper::SetupFunctionParameter(
502 repr::CFunctionLikeIR *functionp, const clang::QualType qual_type,
503 bool has_default_arg, const std::string &source_file, bool is_this_ptr) {
504 if (!CreateBasicNamedAndTypedDecl(qual_type, source_file)) {
505 llvm::errs() << "Setting up function parameter failed\n";
506 return false;
507 }
508 functionp->AddParameter(repr::ParamIR(
509 ast_caches_->GetTypeId(GetKeyForTypeId(qual_type)), has_default_arg,
510 is_this_ptr));
511 return true;
512 }
513
SetupFunctionParameters(repr::FunctionIR * functionp,const std::string & source_file)514 bool FunctionDeclWrapper::SetupFunctionParameters(
515 repr::FunctionIR *functionp,
516 const std::string &source_file) {
517 clang::FunctionDecl::param_const_iterator param_it =
518 function_decl_->param_begin();
519 // If this is a CXXMethodDecl, we need to add the "this" pointer.
520 if (!SetupThisParameter(functionp, source_file)) {
521 llvm::errs() << "Setting up 'this' parameter failed\n";
522 return false;
523 }
524
525 while (param_it != function_decl_->param_end()) {
526 // The linker set key is blank since that shows up in the mangled name.
527 bool has_default_arg = (*param_it)->hasDefaultArg();
528 clang::QualType param_qt = (*param_it)->getType();
529 if (!SetupFunctionParameter(functionp, param_qt, has_default_arg,
530 source_file)) {
531 return false;
532 }
533 param_it++;
534 }
535 return true;
536 }
537
SetupFunction(repr::FunctionIR * functionp,const std::string & source_file)538 bool FunctionDeclWrapper::SetupFunction(repr::FunctionIR *functionp,
539 const std::string &source_file) {
540 // Go through all the parameters in the method and add them to the fields.
541 // Also get the fully qualfied name.
542 // TODO: Change this to get the complete function signature
543 functionp->SetName(function_decl_->getQualifiedNameAsString());
544 functionp->SetSourceFile(source_file);
545 clang::QualType return_type = function_decl_->getReturnType();
546
547 functionp->SetReturnType(
548 ast_caches_->GetTypeId(GetKeyForTypeId(return_type)));
549 functionp->SetAccess(AccessClangToIR(function_decl_->getAccess()));
550 return CreateBasicNamedAndTypedDecl(return_type, source_file) &&
551 SetupFunctionParameters(functionp, source_file) &&
552 SetupTemplateInfo(functionp, source_file);
553 }
554
SetupTemplateInfo(repr::FunctionIR * functionp,const std::string & source_file)555 bool FunctionDeclWrapper::SetupTemplateInfo(repr::FunctionIR *functionp,
556 const std::string &source_file) {
557 switch (function_decl_->getTemplatedKind()) {
558 case clang::FunctionDecl::TK_FunctionTemplateSpecialization: {
559 const clang::TemplateArgumentList *arg_list =
560 function_decl_->getTemplateSpecializationArgs();
561 if (arg_list && !SetupTemplateArguments(arg_list, functionp,
562 source_file)) {
563 return false;
564 }
565 break;
566 }
567 default: {
568 break;
569 }
570 }
571 return true;
572 }
573
GetFunctionDecl()574 std::unique_ptr<repr::FunctionIR> FunctionDeclWrapper::GetFunctionDecl() {
575 auto abi_decl = std::make_unique<repr::FunctionIR>();
576 std::string source_file = GetCachedDeclSourceFile(function_decl_, cip_);
577 if (!SetupFunction(abi_decl.get(), source_file)) {
578 return nullptr;
579 }
580 return abi_decl;
581 }
582
RecordDeclWrapper(clang::MangleContext * mangle_contextp,clang::ASTContext * ast_contextp,const clang::CompilerInstance * compiler_instance_p,const clang::RecordDecl * decl,repr::ModuleIR * module,ASTCaches * ast_caches)583 RecordDeclWrapper::RecordDeclWrapper(
584 clang::MangleContext *mangle_contextp,
585 clang::ASTContext *ast_contextp,
586 const clang::CompilerInstance *compiler_instance_p,
587 const clang::RecordDecl *decl, repr::ModuleIR *module,
588 ASTCaches *ast_caches)
589 : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p, module,
590 ast_caches),
591 record_decl_(decl) {}
592
SetupRecordFields(repr::RecordTypeIR * recordp,const std::string & source_file)593 bool RecordDeclWrapper::SetupRecordFields(repr::RecordTypeIR *recordp,
594 const std::string &source_file) {
595 clang::RecordDecl::field_iterator field = record_decl_->field_begin();
596 uint32_t field_index = 0;
597 const clang::ASTRecordLayout &record_layout =
598 ast_contextp_->getASTRecordLayout(record_decl_);
599 while (field != record_decl_->field_end()) {
600 clang::QualType field_type = field->getType();
601 std::string key_for_type_id = GetKeyForTypeId(field_type);
602 if (const clang::EnumDecl *enum_decl =
603 GetAnonymousEnum(field_type)) {
604 // Handle anonymous enums.
605 key_for_type_id = GetKeyForTypeId(enum_decl->getIntegerType());
606 }
607 if (!CreateBasicNamedAndTypedDecl(field_type, source_file)) {
608 llvm::errs() << "Creation of Type failed\n";
609 return false;
610 }
611 std::string field_name = field->getName();
612 uint64_t field_offset = record_layout.getFieldOffset(field_index);
613 recordp->AddRecordField(repr::RecordFieldIR(
614 field_name, ast_caches_->GetTypeId(key_for_type_id), field_offset,
615 AccessClangToIR(field->getAccess())));
616 field++;
617 field_index++;
618 }
619 return true;
620 }
621
SetupCXXBases(repr::RecordTypeIR * cxxp,const clang::CXXRecordDecl * cxx_record_decl)622 bool RecordDeclWrapper::SetupCXXBases(
623 repr::RecordTypeIR *cxxp, const clang::CXXRecordDecl *cxx_record_decl) {
624 if (!cxx_record_decl || !cxxp) {
625 return false;
626 }
627 clang::CXXRecordDecl::base_class_const_iterator base_class =
628 cxx_record_decl->bases_begin();
629 while (base_class != cxx_record_decl->bases_end()) {
630 std::string name = QualTypeToString(base_class->getType());
631 bool is_virtual = base_class->isVirtual();
632 repr::AccessSpecifierIR access =
633 AccessClangToIR(base_class->getAccessSpecifier());
634 cxxp->AddCXXBaseSpecifier(
635 repr::CXXBaseSpecifierIR(
636 ast_caches_->GetTypeId(GetKeyForTypeId(base_class->getType())),
637 is_virtual, access));
638 base_class++;
639 }
640 return true;
641 }
642
643 typedef std::map<uint64_t, clang::ThunkInfo> ThunkMap;
644
SetupRecordVTable(repr::RecordTypeIR * record_declp,const clang::CXXRecordDecl * cxx_record_decl)645 bool RecordDeclWrapper::SetupRecordVTable(
646 repr::RecordTypeIR *record_declp,
647 const clang::CXXRecordDecl *cxx_record_decl) {
648 if (!cxx_record_decl || !record_declp) {
649 return false;
650 }
651 clang::VTableContextBase *base_vtable_contextp =
652 ast_contextp_->getVTableContext();
653 const clang::Type *typep = cxx_record_decl->getTypeForDecl();
654 if (!base_vtable_contextp || !typep) {
655 return false;
656 }
657 // Skip Microsoft ABI.
658 clang::ItaniumVTableContext *itanium_vtable_contextp =
659 llvm::dyn_cast<clang::ItaniumVTableContext>(base_vtable_contextp);
660 if (!itanium_vtable_contextp || !cxx_record_decl->isPolymorphic() ||
661 typep->isDependentType() || typep->isIncompleteType()) {
662 return true;
663 }
664 const clang::VTableLayout &vtable_layout =
665 itanium_vtable_contextp->getVTableLayout(cxx_record_decl);
666 llvm::ArrayRef<clang::VTableLayout::VTableThunkTy> thunks =
667 vtable_layout.vtable_thunks();
668 ThunkMap thunk_map(thunks.begin(), thunks.end());
669 repr::VTableLayoutIR vtable_ir_layout;
670
671 uint64_t index = 0;
672 for (auto vtable_component : vtable_layout.vtable_components()) {
673 clang::ThunkInfo thunk_info;
674 ThunkMap::iterator it = thunk_map.find(index);
675 if (it != thunk_map.end()) {
676 thunk_info = it->second;
677 }
678 repr::VTableComponentIR added_component =
679 SetupRecordVTableComponent(vtable_component, thunk_info);
680 vtable_ir_layout.AddVTableComponent(std::move(added_component));
681 index++;
682 }
683 record_declp->SetVTableLayout(std::move(vtable_ir_layout));
684 return true;
685 }
686
SetupRecordVTableComponent(const clang::VTableComponent & vtable_component,const clang::ThunkInfo & thunk_info)687 repr::VTableComponentIR RecordDeclWrapper::SetupRecordVTableComponent(
688 const clang::VTableComponent &vtable_component,
689 const clang::ThunkInfo &thunk_info) {
690 repr::VTableComponentIR::Kind kind =
691 repr::VTableComponentIR::Kind::RTTI;
692 std::string mangled_component_name = "";
693 llvm::raw_string_ostream ostream(mangled_component_name);
694 int64_t value = 0;
695 clang::VTableComponent::Kind clang_component_kind =
696 vtable_component.getKind();
697 bool is_pure = false;
698
699 switch (clang_component_kind) {
700 case clang::VTableComponent::CK_VCallOffset:
701 kind = repr::VTableComponentIR::Kind::VCallOffset;
702 value = vtable_component.getVCallOffset().getQuantity();
703 break;
704 case clang::VTableComponent::CK_VBaseOffset:
705 kind = repr::VTableComponentIR::Kind::VBaseOffset;
706 value = vtable_component.getVBaseOffset().getQuantity();
707 break;
708 case clang::VTableComponent::CK_OffsetToTop:
709 kind = repr::VTableComponentIR::Kind::OffsetToTop;
710 value = vtable_component.getOffsetToTop().getQuantity();
711 break;
712 case clang::VTableComponent::CK_RTTI:
713 {
714 kind = repr::VTableComponentIR::Kind::RTTI;
715 const clang::CXXRecordDecl *rtti_decl =
716 vtable_component.getRTTIDecl();
717 assert(rtti_decl != nullptr);
718 mangled_component_name = GetMangledRTTI(rtti_decl);
719 }
720 break;
721 case clang::VTableComponent::CK_FunctionPointer:
722 case clang::VTableComponent::CK_CompleteDtorPointer:
723 case clang::VTableComponent::CK_DeletingDtorPointer:
724 case clang::VTableComponent::CK_UnusedFunctionPointer:
725 {
726 const clang::CXXMethodDecl *method_decl =
727 vtable_component.getFunctionDecl();
728 assert(method_decl != nullptr);
729 is_pure = method_decl->isPure();
730 switch (clang_component_kind) {
731 case clang::VTableComponent::CK_FunctionPointer:
732 kind = repr::VTableComponentIR::Kind::FunctionPointer;
733 if (thunk_info.isEmpty()) {
734 mangle_contextp_->mangleName(method_decl, ostream);
735 } else {
736 mangle_contextp_->mangleThunk(method_decl, thunk_info, ostream);
737 }
738 ostream.flush();
739 break;
740 case clang::VTableComponent::CK_CompleteDtorPointer:
741 case clang::VTableComponent::CK_DeletingDtorPointer:
742 {
743 clang::CXXDtorType dtor_type;
744 if (clang_component_kind ==
745 clang::VTableComponent::CK_CompleteDtorPointer) {
746 dtor_type = clang::CXXDtorType::Dtor_Complete;
747 kind = repr::VTableComponentIR::Kind::CompleteDtorPointer;
748 } else {
749 dtor_type = clang::CXXDtorType::Dtor_Deleting;
750 kind = repr::VTableComponentIR::Kind::DeletingDtorPointer;
751 }
752
753 if (thunk_info.isEmpty()) {
754 mangle_contextp_->mangleCXXDtor(
755 vtable_component.getDestructorDecl(), dtor_type, ostream);
756 } else {
757 mangle_contextp_->mangleCXXDtorThunk(
758 vtable_component.getDestructorDecl(), dtor_type,
759 thunk_info.This, ostream);
760 }
761 ostream.flush();
762 }
763 break;
764 case clang::VTableComponent::CK_UnusedFunctionPointer:
765 kind = repr::VTableComponentIR::Kind::UnusedFunctionPointer;
766 break;
767 default:
768 break;
769 }
770 }
771 break;
772 default:
773 break;
774 }
775 return repr::VTableComponentIR(mangled_component_name, kind, value,
776 is_pure);
777 }
778
SetupTemplateInfo(repr::RecordTypeIR * record_declp,const clang::CXXRecordDecl * cxx_record_decl,const std::string & source_file)779 bool RecordDeclWrapper::SetupTemplateInfo(
780 repr::RecordTypeIR *record_declp,
781 const clang::CXXRecordDecl *cxx_record_decl,
782 const std::string &source_file) {
783 assert(cxx_record_decl != nullptr);
784 const clang::ClassTemplateSpecializationDecl *specialization_decl =
785 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(cxx_record_decl);
786 if (specialization_decl) {
787 const clang::TemplateArgumentList *arg_list =
788 &specialization_decl->getTemplateArgs();
789 if (arg_list &&
790 !SetupTemplateArguments(arg_list, record_declp, source_file)) {
791 return false;
792 }
793 }
794 return true;
795 }
796
SetupRecordInfo(repr::RecordTypeIR * record_declp,const std::string & source_file)797 bool RecordDeclWrapper::SetupRecordInfo(repr::RecordTypeIR *record_declp,
798 const std::string &source_file) {
799 if (!record_declp) {
800 return false;
801 }
802 if (record_decl_->isStruct()) {
803 record_declp->SetRecordKind(
804 repr::RecordTypeIR::RecordKind::struct_kind);
805 } else if (record_decl_->isClass()) {
806 record_declp->SetRecordKind(
807 repr::RecordTypeIR::RecordKind::class_kind);
808 } else {
809 record_declp->SetRecordKind(
810 repr::RecordTypeIR::RecordKind::union_kind);
811 }
812
813 const clang::Type *basic_type = nullptr;
814 if (!(basic_type = record_decl_->getTypeForDecl())) {
815 return false;
816 }
817 clang::QualType qual_type = basic_type->getCanonicalTypeInternal();
818 if (!CreateExtendedType(qual_type, record_declp)) {
819 return false;
820 }
821 record_declp->SetSourceFile(source_file);
822 if (!record_decl_->hasNameForLinkage() ||
823 record_decl_->isAnonymousStructOrUnion()) {
824 record_declp->SetAnonymity(true);
825 }
826 record_declp->SetUniqueId(GetTypeUniqueId(record_decl_));
827 record_declp->SetAccess(AccessClangToIR(record_decl_->getAccess()));
828 return SetupRecordFields(record_declp, source_file) &&
829 SetupCXXRecordInfo(record_declp, source_file);
830 }
831
SetupCXXRecordInfo(repr::RecordTypeIR * record_declp,const std::string & source_file)832 bool RecordDeclWrapper::SetupCXXRecordInfo(repr::RecordTypeIR *record_declp,
833 const std::string &source_file) {
834 const clang::CXXRecordDecl *cxx_record_decl =
835 clang::dyn_cast<clang::CXXRecordDecl>(record_decl_);
836 if (!cxx_record_decl) {
837 return true;
838 }
839 return SetupTemplateInfo(record_declp, cxx_record_decl, source_file) &&
840 SetupCXXBases(record_declp, cxx_record_decl) &&
841 SetupRecordVTable(record_declp, cxx_record_decl);
842 }
843
844 // TODO: Can we use clang's ODR hash to do faster ODR checking?
GetRecordDecl()845 bool RecordDeclWrapper::GetRecordDecl() {
846 auto abi_decl = std::make_unique<repr::RecordTypeIR>();
847 std::string source_file = GetCachedDeclSourceFile(record_decl_, cip_);
848 if (!SetupRecordInfo(abi_decl.get(), source_file)) {
849 llvm::errs() << "Setting up CXX Bases / Template Info failed\n";
850 return false;
851 }
852 if ((abi_decl->GetReferencedType() == "") ||
853 (abi_decl->GetSelfType() == "")) {
854 // The only way to have an empty referenced / self type is when the type was
855 // cached, don't add the record.
856 return true;
857 }
858 return module_->AddLinkableMessage(*abi_decl);
859 }
860
EnumDeclWrapper(clang::MangleContext * mangle_contextp,clang::ASTContext * ast_contextp,const clang::CompilerInstance * compiler_instance_p,const clang::EnumDecl * decl,repr::ModuleIR * module,ASTCaches * ast_caches)861 EnumDeclWrapper::EnumDeclWrapper(
862 clang::MangleContext *mangle_contextp,
863 clang::ASTContext *ast_contextp,
864 const clang::CompilerInstance *compiler_instance_p,
865 const clang::EnumDecl *decl, repr::ModuleIR *module,
866 ASTCaches *ast_caches)
867 : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p, module,
868 ast_caches),
869 enum_decl_(decl) {}
870
SetupEnumFields(repr::EnumTypeIR * enump)871 bool EnumDeclWrapper::SetupEnumFields(repr::EnumTypeIR *enump) {
872 if (!enump) {
873 return false;
874 }
875 clang::EnumDecl::enumerator_iterator enum_it = enum_decl_->enumerator_begin();
876 while (enum_it != enum_decl_->enumerator_end()) {
877 std::string name = enum_it->getQualifiedNameAsString();
878 uint64_t field_value = enum_it->getInitVal().getExtValue();
879 enump->AddEnumField(repr::EnumFieldIR(name, field_value));
880 enum_it++;
881 }
882 return true;
883 }
884
SetupEnum(repr::EnumTypeIR * enum_type,const std::string & source_file)885 bool EnumDeclWrapper::SetupEnum(repr::EnumTypeIR *enum_type,
886 const std::string &source_file) {
887 std::string enum_name = GetTagDeclQualifiedName(enum_decl_);
888 clang::QualType enum_qual_type =
889 enum_decl_->getTypeForDecl()->getCanonicalTypeInternal();
890 if (!CreateExtendedType(enum_qual_type, enum_type)) {
891 return false;
892 }
893 enum_type->SetSourceFile(source_file);
894 enum_type->SetUnderlyingType(
895 ast_caches_->GetTypeId(GetKeyForTypeId(enum_decl_->getIntegerType())));
896 enum_type->SetAccess(AccessClangToIR(enum_decl_->getAccess()));
897 enum_type->SetUniqueId(GetTypeUniqueId(enum_decl_));
898 return SetupEnumFields(enum_type) &&
899 CreateBasicNamedAndTypedDecl(enum_decl_->getIntegerType(), "");
900 }
901
GetEnumDecl()902 bool EnumDeclWrapper::GetEnumDecl() {
903 auto abi_decl = std::make_unique<repr::EnumTypeIR>();
904 std::string source_file = GetCachedDeclSourceFile(enum_decl_, cip_);
905
906 if (!SetupEnum(abi_decl.get(), source_file)) {
907 llvm::errs() << "Setting up Enum failed\n";
908 return false;
909 }
910 return module_->AddLinkableMessage(*abi_decl);
911 }
912
GlobalVarDeclWrapper(clang::MangleContext * mangle_contextp,clang::ASTContext * ast_contextp,const clang::CompilerInstance * compiler_instance_p,const clang::VarDecl * decl,repr::ModuleIR * module,ASTCaches * ast_caches)913 GlobalVarDeclWrapper::GlobalVarDeclWrapper(
914 clang::MangleContext *mangle_contextp,
915 clang::ASTContext *ast_contextp,
916 const clang::CompilerInstance *compiler_instance_p,
917 const clang::VarDecl *decl, repr::ModuleIR *module,
918 ASTCaches *ast_caches)
919 : ABIWrapper(mangle_contextp, ast_contextp, compiler_instance_p, module,
920 ast_caches),
921 global_var_decl_(decl) {}
922
SetupGlobalVar(repr::GlobalVarIR * global_varp,const std::string & source_file)923 bool GlobalVarDeclWrapper::SetupGlobalVar(repr::GlobalVarIR *global_varp,
924 const std::string &source_file) {
925 // Temporary fix: clang segfaults on trying to mangle global variable which
926 // is a dependent sized array type.
927 std::string mangled_name =
928 GetMangledNameDecl(global_var_decl_, mangle_contextp_);
929 if (!CreateBasicNamedAndTypedDecl(global_var_decl_->getType(), source_file)) {
930 return false;
931 }
932 global_varp->SetSourceFile(source_file);
933 global_varp->SetName(global_var_decl_->getQualifiedNameAsString());
934 global_varp->SetLinkerSetKey(mangled_name);
935 global_varp->SetAccess(AccessClangToIR(global_var_decl_->getAccess()));
936 global_varp->SetReferencedType(
937 ast_caches_->GetTypeId(GetKeyForTypeId(global_var_decl_->getType())));
938 return true;
939 }
940
GetGlobalVarDecl()941 bool GlobalVarDeclWrapper::GetGlobalVarDecl() {
942 auto abi_decl = std::make_unique<repr::GlobalVarIR>();
943 std::string source_file = GetCachedDeclSourceFile(global_var_decl_, cip_);
944 return SetupGlobalVar(abi_decl.get(), source_file) &&
945 module_->AddLinkableMessage(*abi_decl);
946 }
947
948
949 } // dumper
950 } // header_checker
951