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