InterfaceStubFunctionsConsumer.cpp 12 KB

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