1 //===--- InterfaceStubFunctionsConsumer.cpp -------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/AST/Mangle.h" 10 #include "clang/AST/RecursiveASTVisitor.h" 11 #include "clang/Basic/TargetInfo.h" 12 #include "clang/Frontend/CompilerInstance.h" 13 #include "clang/Frontend/FrontendActions.h" 14 #include "clang/Sema/TemplateInstCallback.h" 15 #include "llvm/BinaryFormat/ELF.h" 16 17 using namespace clang; 18 19 namespace { 20 class InterfaceStubFunctionsConsumer : public ASTConsumer { 21 CompilerInstance &Instance; 22 StringRef InFile; 23 StringRef Format; 24 std::set<std::string> ParsedTemplates; 25 26 enum RootDeclOrigin { TopLevel = 0, FromTU = 1, IsLate = 2 }; 27 struct MangledSymbol { 28 std::string ParentName; 29 uint8_t Type; 30 uint8_t Binding; 31 std::vector<std::string> Names; 32 MangledSymbol() = delete; 33 34 MangledSymbol(const std::string &ParentName, uint8_t Type, uint8_t Binding, 35 std::vector<std::string> Names) 36 : ParentName(ParentName), Type(Type), Binding(Binding), 37 Names(std::move(Names)) {} 38 }; 39 using MangledSymbols = std::map<const NamedDecl *, MangledSymbol>; 40 41 bool WriteNamedDecl(const NamedDecl *ND, MangledSymbols &Symbols, int RDO) { 42 // Here we filter out anything that's not set to DefaultVisibility. 43 // DefaultVisibility is set on a decl when -fvisibility is not specified on 44 // the command line (or specified as default) and the decl does not have 45 // __attribute__((visibility("hidden"))) set or when the command line 46 // argument is set to hidden but the decl explicitly has 47 // __attribute__((visibility ("default"))) set. We do this so that the user 48 // can have fine grain control of what they want to expose in the stub. 49 auto isVisible = [](const NamedDecl *ND) -> bool { 50 return ND->getVisibility() == DefaultVisibility; 51 }; 52 53 auto ignoreDecl = [this, isVisible](const NamedDecl *ND) -> bool { 54 if (!isVisible(ND)) 55 return true; 56 57 if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { 58 if (const auto *Parent = VD->getParentFunctionOrMethod()) 59 if (isa<BlockDecl>(Parent) || isa<CXXMethodDecl>(Parent)) 60 return true; 61 62 if ((VD->getStorageClass() == StorageClass::SC_Extern) || 63 (VD->getStorageClass() == StorageClass::SC_Static && 64 VD->getParentFunctionOrMethod() == nullptr)) 65 return true; 66 } 67 68 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { 69 if (FD->isInlined() && !isa<CXXMethodDecl>(FD) && 70 !Instance.getLangOpts().GNUInline) 71 return true; 72 if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { 73 if (const auto *RC = dyn_cast<CXXRecordDecl>(MD->getParent())) 74 if (isa<ClassTemplateDecl>(RC->getParent()) || !isVisible(RC)) 75 return true; 76 if (MD->isDependentContext() || !MD->hasBody()) 77 return true; 78 } 79 if (FD->getStorageClass() == StorageClass::SC_Static) 80 return true; 81 } 82 return false; 83 }; 84 85 auto getParentFunctionDecl = [](const NamedDecl *ND) -> const NamedDecl * { 86 if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) 87 if (const auto *FD = 88 dyn_cast_or_null<FunctionDecl>(VD->getParentFunctionOrMethod())) 89 return FD; 90 return nullptr; 91 }; 92 93 auto getMangledNames = [](const NamedDecl *ND) -> std::vector<std::string> { 94 if (!ND) 95 return {""}; 96 ASTNameGenerator NameGen(ND->getASTContext()); 97 std::vector<std::string> MangledNames = NameGen.getAllManglings(ND); 98 if (isa<CXXConstructorDecl>(ND) || isa<CXXDestructorDecl>(ND)) 99 return MangledNames; 100 #ifdef EXPENSIVE_CHECKS 101 assert(MangledNames.size() <= 1 && "Expected only one name mangling."); 102 #endif 103 return {NameGen.getName(ND)}; 104 }; 105 106 if (!(RDO & FromTU)) 107 return true; 108 if (Symbols.find(ND) != Symbols.end()) 109 return true; 110 // - Currently have not figured out how to produce the names for FieldDecls. 111 // - Do not want to produce symbols for function paremeters. 112 if (isa<FieldDecl>(ND) || isa<ParmVarDecl>(ND)) 113 return true; 114 115 const NamedDecl *ParentDecl = getParentFunctionDecl(ND); 116 if ((ParentDecl && ignoreDecl(ParentDecl)) || ignoreDecl(ND)) 117 return true; 118 119 if (RDO & IsLate) { 120 Instance.getDiagnostics().Report(diag::err_asm_invalid_type_in_input) 121 << "Generating Interface Stubs is not supported with " 122 "delayed template parsing."; 123 } else { 124 if (const auto *FD = dyn_cast<FunctionDecl>(ND)) 125 if (FD->isDependentContext()) 126 return true; 127 128 const bool IsWeak = (ND->hasAttr<WeakAttr>() || 129 ND->hasAttr<WeakRefAttr>() || ND->isWeakImported()); 130 131 Symbols.insert(std::make_pair( 132 ND, 133 MangledSymbol(getMangledNames(ParentDecl).front(), 134 // Type: 135 isa<VarDecl>(ND) ? llvm::ELF::STT_OBJECT 136 : llvm::ELF::STT_FUNC, 137 // Binding: 138 IsWeak ? llvm::ELF::STB_WEAK : llvm::ELF::STB_GLOBAL, 139 getMangledNames(ND)))); 140 } 141 return true; 142 } 143 144 void 145 HandleDecls(const llvm::iterator_range<DeclContext::decl_iterator> &Decls, 146 MangledSymbols &Symbols, int RDO) { 147 for (const auto *D : Decls) 148 HandleNamedDecl(dyn_cast<NamedDecl>(D), Symbols, RDO); 149 } 150 151 void HandleTemplateSpecializations(const FunctionTemplateDecl &FTD, 152 MangledSymbols &Symbols, int RDO) { 153 for (const auto *D : FTD.specializations()) 154 HandleNamedDecl(dyn_cast<NamedDecl>(D), Symbols, RDO); 155 } 156 157 void HandleTemplateSpecializations(const ClassTemplateDecl &CTD, 158 MangledSymbols &Symbols, int RDO) { 159 for (const auto *D : CTD.specializations()) 160 HandleNamedDecl(dyn_cast<NamedDecl>(D), Symbols, RDO); 161 } 162 163 bool HandleNamedDecl(const NamedDecl *ND, MangledSymbols &Symbols, int RDO) { 164 if (!ND) 165 return false; 166 167 switch (ND->getKind()) { 168 default: 169 break; 170 case Decl::Kind::Namespace: 171 HandleDecls(cast<NamespaceDecl>(ND)->decls(), Symbols, RDO); 172 return true; 173 case Decl::Kind::CXXRecord: 174 HandleDecls(cast<CXXRecordDecl>(ND)->decls(), Symbols, RDO); 175 return true; 176 case Decl::Kind::ClassTemplateSpecialization: 177 HandleDecls(cast<ClassTemplateSpecializationDecl>(ND)->decls(), Symbols, 178 RDO); 179 return true; 180 case Decl::Kind::ClassTemplate: 181 HandleTemplateSpecializations(*cast<ClassTemplateDecl>(ND), Symbols, RDO); 182 return true; 183 case Decl::Kind::FunctionTemplate: 184 HandleTemplateSpecializations(*cast<FunctionTemplateDecl>(ND), Symbols, 185 RDO); 186 return true; 187 case Decl::Kind::Record: 188 case Decl::Kind::Typedef: 189 case Decl::Kind::Enum: 190 case Decl::Kind::EnumConstant: 191 case Decl::Kind::TemplateTypeParm: 192 case Decl::Kind::NonTypeTemplateParm: 193 case Decl::Kind::CXXConversion: 194 case Decl::Kind::UnresolvedUsingValue: 195 case Decl::Kind::Using: 196 case Decl::Kind::UsingShadow: 197 case Decl::Kind::TypeAliasTemplate: 198 case Decl::Kind::TypeAlias: 199 case Decl::Kind::VarTemplate: 200 case Decl::Kind::VarTemplateSpecialization: 201 case Decl::Kind::UsingDirective: 202 case Decl::Kind::TemplateTemplateParm: 203 case Decl::Kind::ClassTemplatePartialSpecialization: 204 case Decl::Kind::IndirectField: 205 case Decl::Kind::ConstructorUsingShadow: 206 case Decl::Kind::CXXDeductionGuide: 207 case Decl::Kind::NamespaceAlias: 208 case Decl::Kind::UnresolvedUsingTypename: 209 return true; 210 case Decl::Kind::Var: { 211 // Bail on any VarDecl that either has no named symbol. 212 if (!ND->getIdentifier()) 213 return true; 214 const auto *VD = cast<VarDecl>(ND); 215 // Bail on any VarDecl that is a dependent or templated type. 216 if (VD->isTemplated() || VD->getType()->isDependentType()) 217 return true; 218 if (WriteNamedDecl(ND, Symbols, RDO)) 219 return true; 220 break; 221 } 222 case Decl::Kind::ParmVar: 223 case Decl::Kind::CXXMethod: 224 case Decl::Kind::CXXConstructor: 225 case Decl::Kind::CXXDestructor: 226 case Decl::Kind::Function: 227 case Decl::Kind::Field: 228 if (WriteNamedDecl(ND, Symbols, RDO)) 229 return true; 230 } 231 232 // While interface stubs are in the development stage, it's probably best to 233 // catch anything that's not a VarDecl or Template/FunctionDecl. 234 Instance.getDiagnostics().Report(diag::err_asm_invalid_type_in_input) 235 << "Expected a function or function template decl."; 236 return false; 237 } 238 239 public: 240 InterfaceStubFunctionsConsumer(CompilerInstance &Instance, StringRef InFile, 241 StringRef Format) 242 : Instance(Instance), InFile(InFile), Format(Format) {} 243 244 void HandleTranslationUnit(ASTContext &context) override { 245 struct Visitor : public RecursiveASTVisitor<Visitor> { 246 bool VisitNamedDecl(NamedDecl *ND) { 247 if (const auto *FD = dyn_cast<FunctionDecl>(ND)) 248 if (FD->isLateTemplateParsed()) { 249 LateParsedDecls.insert(FD); 250 return true; 251 } 252 253 if (const auto *VD = dyn_cast<ValueDecl>(ND)) { 254 ValueDecls.insert(VD); 255 return true; 256 } 257 258 NamedDecls.insert(ND); 259 return true; 260 } 261 262 std::set<const NamedDecl *> LateParsedDecls; 263 std::set<NamedDecl *> NamedDecls; 264 std::set<const ValueDecl *> ValueDecls; 265 } v; 266 267 v.TraverseDecl(context.getTranslationUnitDecl()); 268 269 MangledSymbols Symbols; 270 auto OS = Instance.createDefaultOutputFile(/*Binary=*/false, InFile, "ifs"); 271 if (!OS) 272 return; 273 274 if (Instance.getLangOpts().DelayedTemplateParsing) { 275 clang::Sema &S = Instance.getSema(); 276 for (const auto *FD : v.LateParsedDecls) { 277 clang::LateParsedTemplate &LPT = 278 *S.LateParsedTemplateMap.find(cast<FunctionDecl>(FD))->second; 279 S.LateTemplateParser(S.OpaqueParser, LPT); 280 HandleNamedDecl(FD, Symbols, (FromTU | IsLate)); 281 } 282 } 283 284 for (const NamedDecl *ND : v.ValueDecls) 285 HandleNamedDecl(ND, Symbols, FromTU); 286 for (const NamedDecl *ND : v.NamedDecls) 287 HandleNamedDecl(ND, Symbols, FromTU); 288 289 auto writeIfsV1 = [this](const llvm::Triple &T, 290 const MangledSymbols &Symbols, 291 const ASTContext &context, StringRef Format, 292 raw_ostream &OS) -> void { 293 OS << "--- !" << Format << "\n"; 294 OS << "IfsVersion: 3.0\n"; 295 OS << "Target: " << T.str() << "\n"; 296 OS << "Symbols:\n"; 297 for (const auto &E : Symbols) { 298 const MangledSymbol &Symbol = E.second; 299 for (const auto &Name : Symbol.Names) { 300 OS << " - { Name: \"" 301 << (Symbol.ParentName.empty() || Instance.getLangOpts().CPlusPlus 302 ? "" 303 : (Symbol.ParentName + ".")) 304 << Name << "\", Type: "; 305 switch (Symbol.Type) { 306 default: 307 llvm_unreachable( 308 "clang -emit-interface-stubs: Unexpected symbol type."); 309 case llvm::ELF::STT_NOTYPE: 310 OS << "NoType"; 311 break; 312 case llvm::ELF::STT_OBJECT: { 313 auto VD = cast<ValueDecl>(E.first)->getType(); 314 OS << "Object, Size: " 315 << context.getTypeSizeInChars(VD).getQuantity(); 316 break; 317 } 318 case llvm::ELF::STT_FUNC: 319 OS << "Func"; 320 break; 321 } 322 if (Symbol.Binding == llvm::ELF::STB_WEAK) 323 OS << ", Weak: true"; 324 OS << " }\n"; 325 } 326 } 327 OS << "...\n"; 328 OS.flush(); 329 }; 330 331 assert(Format == "ifs-v1" && "Unexpected IFS Format."); 332 writeIfsV1(Instance.getTarget().getTriple(), Symbols, context, Format, *OS); 333 } 334 }; 335 } // namespace 336 337 std::unique_ptr<ASTConsumer> 338 GenerateInterfaceStubsAction::CreateASTConsumer(CompilerInstance &CI, 339 StringRef InFile) { 340 return std::make_unique<InterfaceStubFunctionsConsumer>(CI, InFile, "ifs-v1"); 341 } 342