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