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