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