clang  19.0.0git
ObjectFilePCHContainerOperations.cpp
Go to the documentation of this file.
1 //===--- ObjectFilePCHContainerOperations.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 
10 #include "CGDebugInfo.h"
11 #include "CodeGenModule.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/AST/DeclObjC.h"
14 #include "clang/AST/Expr.h"
17 #include "clang/Basic/Diagnostic.h"
18 #include "clang/Basic/TargetInfo.h"
21 #include "clang/Lex/HeaderSearch.h"
22 #include "clang/Lex/Preprocessor.h"
23 #include "llvm/ADT/StringRef.h"
24 #include "llvm/Bitstream/BitstreamReader.h"
25 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
26 #include "llvm/IR/Constants.h"
27 #include "llvm/IR/DataLayout.h"
28 #include "llvm/IR/LLVMContext.h"
29 #include "llvm/IR/Module.h"
30 #include "llvm/MC/TargetRegistry.h"
31 #include "llvm/Object/COFF.h"
32 #include "llvm/Object/ObjectFile.h"
33 #include "llvm/Support/Path.h"
34 #include <memory>
35 #include <utility>
36 
37 using namespace clang;
38 
39 #define DEBUG_TYPE "pchcontainer"
40 
41 namespace {
42 class PCHContainerGenerator : public ASTConsumer {
43  DiagnosticsEngine &Diags;
44  const std::string MainFileName;
45  const std::string OutputFileName;
46  ASTContext *Ctx;
47  ModuleMap &MMap;
49  const HeaderSearchOptions &HeaderSearchOpts;
50  const PreprocessorOptions &PreprocessorOpts;
51  CodeGenOptions CodeGenOpts;
52  const TargetOptions TargetOpts;
53  LangOptions LangOpts;
54  std::unique_ptr<llvm::LLVMContext> VMContext;
55  std::unique_ptr<llvm::Module> M;
56  std::unique_ptr<CodeGen::CodeGenModule> Builder;
57  std::unique_ptr<raw_pwrite_stream> OS;
58  std::shared_ptr<PCHBuffer> Buffer;
59 
60  /// Visit every type and emit debug info for it.
61  struct DebugTypeVisitor : public RecursiveASTVisitor<DebugTypeVisitor> {
63  ASTContext &Ctx;
64  DebugTypeVisitor(clang::CodeGen::CGDebugInfo &DI, ASTContext &Ctx)
65  : DI(DI), Ctx(Ctx) {}
66 
67  /// Determine whether this type can be represented in DWARF.
68  static bool CanRepresent(const Type *Ty) {
69  return !Ty->isDependentType() && !Ty->isUndeducedType();
70  }
71 
72  bool VisitImportDecl(ImportDecl *D) {
73  if (!D->getImportedOwningModule())
74  DI.EmitImportDecl(*D);
75  return true;
76  }
77 
78  bool VisitTypeDecl(TypeDecl *D) {
79  // TagDecls may be deferred until after all decls have been merged and we
80  // know the complete type. Pure forward declarations will be skipped, but
81  // they don't need to be emitted into the module anyway.
82  if (auto *TD = dyn_cast<TagDecl>(D))
83  if (!TD->isCompleteDefinition())
84  return true;
85 
86  QualType QualTy = Ctx.getTypeDeclType(D);
87  if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr()))
88  DI.getOrCreateStandaloneType(QualTy, D->getLocation());
89  return true;
90  }
91 
92  bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
93  QualType QualTy(D->getTypeForDecl(), 0);
94  if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr()))
95  DI.getOrCreateStandaloneType(QualTy, D->getLocation());
96  return true;
97  }
98 
99  bool VisitFunctionDecl(FunctionDecl *D) {
100  // Skip deduction guides.
101  if (isa<CXXDeductionGuideDecl>(D))
102  return true;
103 
104  if (isa<CXXMethodDecl>(D))
105  // This is not yet supported. Constructing the `this' argument
106  // mandates a CodeGenFunction.
107  return true;
108 
109  SmallVector<QualType, 16> ArgTypes;
110  for (auto *i : D->parameters())
111  ArgTypes.push_back(i->getType());
112  QualType RetTy = D->getReturnType();
113  QualType FnTy = Ctx.getFunctionType(RetTy, ArgTypes,
115  if (CanRepresent(FnTy.getTypePtr()))
116  DI.EmitFunctionDecl(D, D->getLocation(), FnTy);
117  return true;
118  }
119 
120  bool VisitObjCMethodDecl(ObjCMethodDecl *D) {
121  if (!D->getClassInterface())
122  return true;
123 
124  bool selfIsPseudoStrong, selfIsConsumed;
125  SmallVector<QualType, 16> ArgTypes;
126  ArgTypes.push_back(D->getSelfType(Ctx, D->getClassInterface(),
127  selfIsPseudoStrong, selfIsConsumed));
128  ArgTypes.push_back(Ctx.getObjCSelType());
129  for (auto *i : D->parameters())
130  ArgTypes.push_back(i->getType());
131  QualType RetTy = D->getReturnType();
132  QualType FnTy = Ctx.getFunctionType(RetTy, ArgTypes,
134  if (CanRepresent(FnTy.getTypePtr()))
135  DI.EmitFunctionDecl(D, D->getLocation(), FnTy);
136  return true;
137  }
138  };
139 
140 public:
141  PCHContainerGenerator(CompilerInstance &CI, const std::string &MainFileName,
142  const std::string &OutputFileName,
143  std::unique_ptr<raw_pwrite_stream> OS,
144  std::shared_ptr<PCHBuffer> Buffer)
145  : Diags(CI.getDiagnostics()), MainFileName(MainFileName),
146  OutputFileName(OutputFileName), Ctx(nullptr),
148  FS(&CI.getVirtualFileSystem()),
149  HeaderSearchOpts(CI.getHeaderSearchOpts()),
150  PreprocessorOpts(CI.getPreprocessorOpts()),
151  TargetOpts(CI.getTargetOpts()), LangOpts(CI.getLangOpts()),
152  OS(std::move(OS)), Buffer(std::move(Buffer)) {
153  // The debug info output isn't affected by CodeModel and
154  // ThreadModel, but the backend expects them to be nonempty.
155  CodeGenOpts.CodeModel = "default";
156  LangOpts.setThreadModel(LangOptions::ThreadModelKind::Single);
157  CodeGenOpts.DebugTypeExtRefs = true;
158  // When building a module MainFileName is the name of the modulemap file.
159  CodeGenOpts.MainFileName =
160  LangOpts.CurrentModule.empty() ? MainFileName : LangOpts.CurrentModule;
161  CodeGenOpts.setDebugInfo(llvm::codegenoptions::FullDebugInfo);
162  CodeGenOpts.setDebuggerTuning(CI.getCodeGenOpts().getDebuggerTuning());
163  CodeGenOpts.DwarfVersion = CI.getCodeGenOpts().DwarfVersion;
164  CodeGenOpts.DebugCompilationDir =
166  CodeGenOpts.DebugPrefixMap =
168  CodeGenOpts.DebugStrictDwarf = CI.getCodeGenOpts().DebugStrictDwarf;
169  }
170 
171  ~PCHContainerGenerator() override = default;
172 
173  void Initialize(ASTContext &Context) override {
174  assert(!Ctx && "initialized multiple times");
175 
176  Ctx = &Context;
177  VMContext.reset(new llvm::LLVMContext());
178  M.reset(new llvm::Module(MainFileName, *VMContext));
179  M->setDataLayout(Ctx->getTargetInfo().getDataLayoutString());
180  Builder.reset(new CodeGen::CodeGenModule(
181  *Ctx, FS, HeaderSearchOpts, PreprocessorOpts, CodeGenOpts, *M, Diags));
182 
183  // Prepare CGDebugInfo to emit debug info for a clang module.
184  auto *DI = Builder->getModuleDebugInfo();
185  StringRef ModuleName = llvm::sys::path::filename(MainFileName);
186  DI->setPCHDescriptor(
187  {ModuleName, "", OutputFileName, ASTFileSignature::createDISentinel()});
188  DI->setModuleMap(MMap);
189  }
190 
191  bool HandleTopLevelDecl(DeclGroupRef D) override {
192  if (Diags.hasErrorOccurred())
193  return true;
194 
195  // Collect debug info for all decls in this group.
196  for (auto *I : D)
197  if (!I->isFromASTFile()) {
198  DebugTypeVisitor DTV(*Builder->getModuleDebugInfo(), *Ctx);
199  DTV.TraverseDecl(I);
200  }
201  return true;
202  }
203 
204  void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override {
205  HandleTopLevelDecl(D);
206  }
207 
208  void HandleTagDeclDefinition(TagDecl *D) override {
209  if (Diags.hasErrorOccurred())
210  return;
211 
212  if (D->isFromASTFile())
213  return;
214 
215  // Anonymous tag decls are deferred until we are building their declcontext.
216  if (D->getName().empty())
217  return;
218 
219  // Defer tag decls until their declcontext is complete.
220  auto *DeclCtx = D->getDeclContext();
221  while (DeclCtx) {
222  if (auto *D = dyn_cast<TagDecl>(DeclCtx))
223  if (!D->isCompleteDefinition())
224  return;
225  DeclCtx = DeclCtx->getParent();
226  }
227 
228  DebugTypeVisitor DTV(*Builder->getModuleDebugInfo(), *Ctx);
229  DTV.TraverseDecl(D);
230  Builder->UpdateCompletedType(D);
231  }
232 
233  void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
234  if (Diags.hasErrorOccurred())
235  return;
236 
237  if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
238  Builder->getModuleDebugInfo()->completeRequiredType(RD);
239  }
240 
241  void HandleImplicitImportDecl(ImportDecl *D) override {
242  if (!D->getImportedOwningModule())
243  Builder->getModuleDebugInfo()->EmitImportDecl(*D);
244  }
245 
246  /// Emit a container holding the serialized AST.
247  void HandleTranslationUnit(ASTContext &Ctx) override {
248  assert(M && VMContext && Builder);
249  // Delete these on function exit.
250  std::unique_ptr<llvm::LLVMContext> VMContext = std::move(this->VMContext);
251  std::unique_ptr<llvm::Module> M = std::move(this->M);
252  std::unique_ptr<CodeGen::CodeGenModule> Builder = std::move(this->Builder);
253 
254  if (Diags.hasErrorOccurred())
255  return;
256 
257  M->setTargetTriple(Ctx.getTargetInfo().getTriple().getTriple());
258  M->setDataLayout(Ctx.getTargetInfo().getDataLayoutString());
259 
260  // PCH files don't have a signature field in the control block,
261  // but LLVM detects DWO CUs by looking for a non-zero DWO id.
262  // We use the lower 64 bits for debug info.
263 
264  uint64_t Signature =
265  Buffer->Signature ? Buffer->Signature.truncatedValue() : ~1ULL;
266 
267  Builder->getModuleDebugInfo()->setDwoId(Signature);
268 
269  // Finalize the Builder.
270  if (Builder)
271  Builder->Release();
272 
273  // Ensure the target exists.
274  std::string Error;
275  auto Triple = Ctx.getTargetInfo().getTriple();
276  if (!llvm::TargetRegistry::lookupTarget(Triple.getTriple(), Error))
277  llvm::report_fatal_error(llvm::Twine(Error));
278 
279  // Emit the serialized Clang AST into its own section.
280  assert(Buffer->IsComplete && "serialization did not complete");
281  auto &SerializedAST = Buffer->Data;
282  auto Size = SerializedAST.size();
283 
284  if (Triple.isOSBinFormatWasm()) {
285  // Emit __clangast in custom section instead of named data segment
286  // to find it while iterating sections.
287  // This could be avoided if all data segements (the wasm sense) were
288  // represented as their own sections (in the llvm sense).
289  // TODO: https://github.com/WebAssembly/tool-conventions/issues/138
290  llvm::NamedMDNode *MD =
291  M->getOrInsertNamedMetadata("wasm.custom_sections");
292  llvm::Metadata *Ops[2] = {
293  llvm::MDString::get(*VMContext, "__clangast"),
294  llvm::MDString::get(*VMContext,
295  StringRef(SerializedAST.data(), Size))};
296  auto *NameAndContent = llvm::MDTuple::get(*VMContext, Ops);
297  MD->addOperand(NameAndContent);
298  } else {
299  auto Int8Ty = llvm::Type::getInt8Ty(*VMContext);
300  auto *Ty = llvm::ArrayType::get(Int8Ty, Size);
301  auto *Data = llvm::ConstantDataArray::getString(
302  *VMContext, StringRef(SerializedAST.data(), Size),
303  /*AddNull=*/false);
304  auto *ASTSym = new llvm::GlobalVariable(
305  *M, Ty, /*constant*/ true, llvm::GlobalVariable::InternalLinkage,
306  Data, "__clang_ast");
307  // The on-disk hashtable needs to be aligned.
308  ASTSym->setAlignment(llvm::Align(8));
309 
310  // Mach-O also needs a segment name.
311  if (Triple.isOSBinFormatMachO())
312  ASTSym->setSection("__CLANG,__clangast");
313  // COFF has an eight character length limit.
314  else if (Triple.isOSBinFormatCOFF())
315  ASTSym->setSection("clangast");
316  else
317  ASTSym->setSection("__clangast");
318  }
319 
320  LLVM_DEBUG({
321  // Print the IR for the PCH container to the debug output.
322  llvm::SmallString<0> Buffer;
324  Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts, LangOpts,
325  Ctx.getTargetInfo().getDataLayoutString(), M.get(),
327  std::make_unique<llvm::raw_svector_ostream>(Buffer));
328  llvm::dbgs() << Buffer;
329  });
330 
331  // Use the LLVM backend to emit the pch container.
332  clang::EmitBackendOutput(Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts,
333  LangOpts,
334  Ctx.getTargetInfo().getDataLayoutString(), M.get(),
335  BackendAction::Backend_EmitObj, FS, std::move(OS));
336 
337  // Free the memory for the temporary buffer.
339  SerializedAST = std::move(Empty);
340  }
341 };
342 
343 } // anonymous namespace
344 
345 std::unique_ptr<ASTConsumer>
346 ObjectFilePCHContainerWriter::CreatePCHContainerGenerator(
347  CompilerInstance &CI, const std::string &MainFileName,
348  const std::string &OutputFileName,
349  std::unique_ptr<llvm::raw_pwrite_stream> OS,
350  std::shared_ptr<PCHBuffer> Buffer) const {
351  return std::make_unique<PCHContainerGenerator>(
352  CI, MainFileName, OutputFileName, std::move(OS), Buffer);
353 }
354 
355 ArrayRef<StringRef> ObjectFilePCHContainerReader::getFormats() const {
356  static StringRef Formats[] = {"obj", "raw"};
357  return Formats;
358 }
359 
360 StringRef
361 ObjectFilePCHContainerReader::ExtractPCH(llvm::MemoryBufferRef Buffer) const {
362  StringRef PCH;
363  auto OFOrErr = llvm::object::ObjectFile::createObjectFile(Buffer);
364  if (OFOrErr) {
365  auto &OF = OFOrErr.get();
366  bool IsCOFF = isa<llvm::object::COFFObjectFile>(*OF);
367  // Find the clang AST section in the container.
368  for (auto &Section : OF->sections()) {
369  StringRef Name;
370  if (Expected<StringRef> NameOrErr = Section.getName())
371  Name = *NameOrErr;
372  else
373  consumeError(NameOrErr.takeError());
374 
375  if ((!IsCOFF && Name == "__clangast") || (IsCOFF && Name == "clangast")) {
376  if (Expected<StringRef> E = Section.getContents())
377  return *E;
378  else {
379  handleAllErrors(E.takeError(), [&](const llvm::ErrorInfoBase &EIB) {
380  EIB.log(llvm::errs());
381  });
382  return "";
383  }
384  }
385  }
386  }
387  handleAllErrors(OFOrErr.takeError(), [&](const llvm::ErrorInfoBase &EIB) {
388  if (EIB.convertToErrorCode() ==
389  llvm::object::object_error::invalid_file_type)
390  // As a fallback, treat the buffer as a raw AST.
391  PCH = Buffer.getBuffer();
392  else
393  EIB.log(llvm::errs());
394  });
395  return PCH;
396 }
Defines the clang::ASTContext interface.
Defines the Diagnostic-related interfaces.
Defines the clang::Preprocessor interface.
const char * Data
ASTConsumer - This is an abstract interface that should be implemented by clients that read ASTs.
Definition: ASTConsumer.h:33
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:185
QualType getTypeDeclType(const TypeDecl *Decl, const TypeDecl *PrevDecl=nullptr) const
Return the unique reference to the type for the specified type declaration.
Definition: ASTContext.h:1605
QualType getObjCSelType() const
Retrieve the type that corresponds to the predefined Objective-C 'SEL' type.
Definition: ASTContext.h:2088
QualType getFunctionType(QualType ResultTy, ArrayRef< QualType > Args, const FunctionProtoType::ExtProtoInfo &EPI) const
Return a normal function type with a typed argument list.
Definition: ASTContext.h:1583
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:760
CodeGenOptions - Track various options which control how the code is optimized and passed to the back...
llvm::SmallVector< std::pair< std::string, std::string >, 0 > DebugPrefixMap
std::string CodeModel
The code model to use (-mcmodel).
std::string DebugCompilationDir
The string to embed in debug information as the current working directory.
std::string MainFileName
The user provided name for the "main file", if non-empty.
This class gathers all debug information during compilation and is responsible for emitting to llvm g...
Definition: CGDebugInfo.h:55
llvm::DIType * getOrCreateStandaloneType(QualType Ty, SourceLocation Loc)
Emit standalone debug info for a type.
void EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, QualType FnType, llvm::Function *Fn=nullptr)
Emit debug info for a function declaration.
void EmitImportDecl(const ImportDecl &ID)
Emit an @import declaration.
This class organizes the cross-function state that is used while generating LLVM code.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
CodeGenOptions & getCodeGenOpts()
CompilerInvocation & getInvocation()
Preprocessor & getPreprocessor() const
Return the current preprocessor.
PreprocessorOptions & getPreprocessorOpts()
TargetOptions & getTargetOpts()
HeaderSearchOptions & getHeaderSearchOpts()
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
llvm::vfs::FileSystem & getVirtualFileSystem() const
LangOptions & getLangOpts()
CodeGenOptions & getCodeGenOpts()
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition: DeclBase.h:2066
bool isFromASTFile() const
Determine whether this declaration came from an AST file (such as a precompiled header or module) rat...
Definition: DeclBase.h:776
SourceLocation getLocation() const
Definition: DeclBase.h:445
Module * getImportedOwningModule() const
Get the imported owning module, if this decl is from an imported (non-local) module.
Definition: DeclBase.h:803
DeclContext * getDeclContext()
Definition: DeclBase.h:454
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:193
bool hasErrorOccurred() const
Definition: Diagnostic.h:849
Represents a function declaration or definition.
Definition: Decl.h:1972
QualType getReturnType() const
Definition: Decl.h:2757
ArrayRef< ParmVarDecl * > parameters() const
Definition: Decl.h:2686
HeaderSearchOptions - Helper class for storing options related to the initialization of the HeaderSea...
ModuleMap & getModuleMap()
Retrieve the module map.
Definition: HeaderSearch.h:837
Describes a module import declaration, which makes the contents of the named module visible in the cu...
Definition: Decl.h:4802
@ Single
Single Threaded Environment.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:482
std::string CurrentModule
The name of the current module, of which the main source file is a part.
Definition: LangOptions.h:537
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:276
Represents an ObjC class declaration.
Definition: DeclObjC.h:1153
const Type * getTypeForDecl() const
Definition: DeclObjC.h:1917
ObjCMethodDecl - Represents an instance or class method declaration.
Definition: DeclObjC.h:140
QualType getSelfType(ASTContext &Context, const ObjCInterfaceDecl *OID, bool &selfIsPseudoStrong, bool &selfIsConsumed) const
Definition: DeclObjC.cpp:1145
QualType getReturnType() const
Definition: DeclObjC.h:329
ObjCInterfaceDecl * getClassInterface()
Definition: DeclObjC.cpp:1211
ArrayRef< ParmVarDecl * > parameters() const
Definition: DeclObjC.h:373
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
HeaderSearch & getHeaderSearchInfo() const
A (possibly-)qualified type.
Definition: Type.h:940
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:1007
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:7371
Represents a struct/union/class.
Definition: Decl.h:4171
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Represents the declaration of a struct/union/class/enum.
Definition: Decl.h:3587
bool isCompleteDefinition() const
Return true if this decl has its body fully specified.
Definition: Decl.h:3690
const char * getDataLayoutString() const
Definition: TargetInfo.h:1265
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:1256
Options for controlling the target.
Definition: TargetOptions.h:26
Represents a declaration of a type.
Definition: Decl.h:3393
The base class of the type hierarchy.
Definition: Type.h:1813
bool isDependentType() const
Whether this type is a dependent type, meaning that its definition somehow depends on a template para...
Definition: Type.h:2661
bool isUndeducedType() const
Determine whether this type is an undeduced type, meaning that it somehow involves a C++11 'auto' typ...
Definition: Type.h:8073
Defines the clang::TargetInfo interface.
The JSON file list parser is used to communicate input to InstallAPI.
void EmitBackendOutput(DiagnosticsEngine &Diags, const HeaderSearchOptions &, const CodeGenOptions &CGOpts, const TargetOptions &TOpts, const LangOptions &LOpts, StringRef TDesc, llvm::Module *M, BackendAction Action, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, std::unique_ptr< raw_pwrite_stream > OS, BackendConsumer *BC=nullptr)
@ Backend_EmitLL
Emit human-readable LLVM assembly.
Definition: BackendUtil.h:38
@ Backend_EmitObj
Emit native object files.
Definition: BackendUtil.h:41
@ PCH
Disable validation for a precompiled header and the modules it depends on.
unsigned long uint64_t
static ASTFileSignature createDISentinel()
Definition: Module.h:79
Extra information about a function prototype.
Definition: Type.h:4747