Coverage Report

Created: 2019-07-24 05:18

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