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