InterfaceStubFunctionsConsumer.cpp 11 KB

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