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