1e5dd7070Spatrick //===--- ObjectFilePCHContainerOperations.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/CodeGen/ObjectFilePCHContainerOperations.h"
10e5dd7070Spatrick #include "CGDebugInfo.h"
11e5dd7070Spatrick #include "CodeGenModule.h"
12e5dd7070Spatrick #include "clang/AST/ASTContext.h"
13e5dd7070Spatrick #include "clang/AST/DeclObjC.h"
14e5dd7070Spatrick #include "clang/AST/Expr.h"
15e5dd7070Spatrick #include "clang/AST/RecursiveASTVisitor.h"
16e5dd7070Spatrick #include "clang/Basic/CodeGenOptions.h"
17e5dd7070Spatrick #include "clang/Basic/Diagnostic.h"
18e5dd7070Spatrick #include "clang/Basic/TargetInfo.h"
19e5dd7070Spatrick #include "clang/CodeGen/BackendUtil.h"
20e5dd7070Spatrick #include "clang/Frontend/CompilerInstance.h"
21e5dd7070Spatrick #include "clang/Lex/HeaderSearch.h"
22e5dd7070Spatrick #include "clang/Lex/Preprocessor.h"
23e5dd7070Spatrick #include "llvm/ADT/StringRef.h"
24e5dd7070Spatrick #include "llvm/Bitstream/BitstreamReader.h"
25e5dd7070Spatrick #include "llvm/DebugInfo/DWARF/DWARFContext.h"
26e5dd7070Spatrick #include "llvm/IR/Constants.h"
27e5dd7070Spatrick #include "llvm/IR/DataLayout.h"
28e5dd7070Spatrick #include "llvm/IR/LLVMContext.h"
29e5dd7070Spatrick #include "llvm/IR/Module.h"
30*12c85518Srobert #include "llvm/MC/TargetRegistry.h"
31e5dd7070Spatrick #include "llvm/Object/COFF.h"
32e5dd7070Spatrick #include "llvm/Object/ObjectFile.h"
33e5dd7070Spatrick #include "llvm/Support/Path.h"
34e5dd7070Spatrick #include <memory>
35e5dd7070Spatrick #include <utility>
36e5dd7070Spatrick
37e5dd7070Spatrick using namespace clang;
38e5dd7070Spatrick
39e5dd7070Spatrick #define DEBUG_TYPE "pchcontainer"
40e5dd7070Spatrick
41e5dd7070Spatrick namespace {
42e5dd7070Spatrick class PCHContainerGenerator : public ASTConsumer {
43e5dd7070Spatrick DiagnosticsEngine &Diags;
44e5dd7070Spatrick const std::string MainFileName;
45e5dd7070Spatrick const std::string OutputFileName;
46e5dd7070Spatrick ASTContext *Ctx;
47e5dd7070Spatrick ModuleMap &MMap;
48*12c85518Srobert IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
49e5dd7070Spatrick const HeaderSearchOptions &HeaderSearchOpts;
50e5dd7070Spatrick const PreprocessorOptions &PreprocessorOpts;
51e5dd7070Spatrick CodeGenOptions CodeGenOpts;
52e5dd7070Spatrick const TargetOptions TargetOpts;
53a9ac8606Spatrick LangOptions LangOpts;
54e5dd7070Spatrick std::unique_ptr<llvm::LLVMContext> VMContext;
55e5dd7070Spatrick std::unique_ptr<llvm::Module> M;
56e5dd7070Spatrick std::unique_ptr<CodeGen::CodeGenModule> Builder;
57e5dd7070Spatrick std::unique_ptr<raw_pwrite_stream> OS;
58e5dd7070Spatrick std::shared_ptr<PCHBuffer> Buffer;
59e5dd7070Spatrick
60e5dd7070Spatrick /// Visit every type and emit debug info for it.
61e5dd7070Spatrick struct DebugTypeVisitor : public RecursiveASTVisitor<DebugTypeVisitor> {
62e5dd7070Spatrick clang::CodeGen::CGDebugInfo &DI;
63e5dd7070Spatrick ASTContext &Ctx;
DebugTypeVisitor__anon622f1b6e0111::PCHContainerGenerator::DebugTypeVisitor64e5dd7070Spatrick DebugTypeVisitor(clang::CodeGen::CGDebugInfo &DI, ASTContext &Ctx)
65e5dd7070Spatrick : DI(DI), Ctx(Ctx) {}
66e5dd7070Spatrick
67e5dd7070Spatrick /// Determine whether this type can be represented in DWARF.
CanRepresent__anon622f1b6e0111::PCHContainerGenerator::DebugTypeVisitor68e5dd7070Spatrick static bool CanRepresent(const Type *Ty) {
69e5dd7070Spatrick return !Ty->isDependentType() && !Ty->isUndeducedType();
70e5dd7070Spatrick }
71e5dd7070Spatrick
VisitImportDecl__anon622f1b6e0111::PCHContainerGenerator::DebugTypeVisitor72e5dd7070Spatrick bool VisitImportDecl(ImportDecl *D) {
73e5dd7070Spatrick if (!D->getImportedOwningModule())
74e5dd7070Spatrick DI.EmitImportDecl(*D);
75e5dd7070Spatrick return true;
76e5dd7070Spatrick }
77e5dd7070Spatrick
VisitTypeDecl__anon622f1b6e0111::PCHContainerGenerator::DebugTypeVisitor78e5dd7070Spatrick bool VisitTypeDecl(TypeDecl *D) {
79e5dd7070Spatrick // TagDecls may be deferred until after all decls have been merged and we
80e5dd7070Spatrick // know the complete type. Pure forward declarations will be skipped, but
81e5dd7070Spatrick // they don't need to be emitted into the module anyway.
82e5dd7070Spatrick if (auto *TD = dyn_cast<TagDecl>(D))
83e5dd7070Spatrick if (!TD->isCompleteDefinition())
84e5dd7070Spatrick return true;
85e5dd7070Spatrick
86e5dd7070Spatrick QualType QualTy = Ctx.getTypeDeclType(D);
87e5dd7070Spatrick if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr()))
88e5dd7070Spatrick DI.getOrCreateStandaloneType(QualTy, D->getLocation());
89e5dd7070Spatrick return true;
90e5dd7070Spatrick }
91e5dd7070Spatrick
VisitObjCInterfaceDecl__anon622f1b6e0111::PCHContainerGenerator::DebugTypeVisitor92e5dd7070Spatrick bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
93e5dd7070Spatrick QualType QualTy(D->getTypeForDecl(), 0);
94e5dd7070Spatrick if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr()))
95e5dd7070Spatrick DI.getOrCreateStandaloneType(QualTy, D->getLocation());
96e5dd7070Spatrick return true;
97e5dd7070Spatrick }
98e5dd7070Spatrick
VisitFunctionDecl__anon622f1b6e0111::PCHContainerGenerator::DebugTypeVisitor99e5dd7070Spatrick bool VisitFunctionDecl(FunctionDecl *D) {
100*12c85518Srobert // Skip deduction guides.
101*12c85518Srobert if (isa<CXXDeductionGuideDecl>(D))
102*12c85518Srobert return true;
103*12c85518Srobert
104e5dd7070Spatrick if (isa<CXXMethodDecl>(D))
105e5dd7070Spatrick // This is not yet supported. Constructing the `this' argument
106e5dd7070Spatrick // mandates a CodeGenFunction.
107e5dd7070Spatrick return true;
108e5dd7070Spatrick
109e5dd7070Spatrick SmallVector<QualType, 16> ArgTypes;
110*12c85518Srobert for (auto *i : D->parameters())
111e5dd7070Spatrick ArgTypes.push_back(i->getType());
112e5dd7070Spatrick QualType RetTy = D->getReturnType();
113e5dd7070Spatrick QualType FnTy = Ctx.getFunctionType(RetTy, ArgTypes,
114e5dd7070Spatrick FunctionProtoType::ExtProtoInfo());
115e5dd7070Spatrick if (CanRepresent(FnTy.getTypePtr()))
116e5dd7070Spatrick DI.EmitFunctionDecl(D, D->getLocation(), FnTy);
117e5dd7070Spatrick return true;
118e5dd7070Spatrick }
119e5dd7070Spatrick
VisitObjCMethodDecl__anon622f1b6e0111::PCHContainerGenerator::DebugTypeVisitor120e5dd7070Spatrick bool VisitObjCMethodDecl(ObjCMethodDecl *D) {
121e5dd7070Spatrick if (!D->getClassInterface())
122e5dd7070Spatrick return true;
123e5dd7070Spatrick
124e5dd7070Spatrick bool selfIsPseudoStrong, selfIsConsumed;
125e5dd7070Spatrick SmallVector<QualType, 16> ArgTypes;
126e5dd7070Spatrick ArgTypes.push_back(D->getSelfType(Ctx, D->getClassInterface(),
127e5dd7070Spatrick selfIsPseudoStrong, selfIsConsumed));
128e5dd7070Spatrick ArgTypes.push_back(Ctx.getObjCSelType());
129*12c85518Srobert for (auto *i : D->parameters())
130e5dd7070Spatrick ArgTypes.push_back(i->getType());
131e5dd7070Spatrick QualType RetTy = D->getReturnType();
132e5dd7070Spatrick QualType FnTy = Ctx.getFunctionType(RetTy, ArgTypes,
133e5dd7070Spatrick FunctionProtoType::ExtProtoInfo());
134e5dd7070Spatrick if (CanRepresent(FnTy.getTypePtr()))
135e5dd7070Spatrick DI.EmitFunctionDecl(D, D->getLocation(), FnTy);
136e5dd7070Spatrick return true;
137e5dd7070Spatrick }
138e5dd7070Spatrick };
139e5dd7070Spatrick
140e5dd7070Spatrick public:
PCHContainerGenerator(CompilerInstance & CI,const std::string & MainFileName,const std::string & OutputFileName,std::unique_ptr<raw_pwrite_stream> OS,std::shared_ptr<PCHBuffer> Buffer)141e5dd7070Spatrick PCHContainerGenerator(CompilerInstance &CI, const std::string &MainFileName,
142e5dd7070Spatrick const std::string &OutputFileName,
143e5dd7070Spatrick std::unique_ptr<raw_pwrite_stream> OS,
144e5dd7070Spatrick std::shared_ptr<PCHBuffer> Buffer)
145e5dd7070Spatrick : Diags(CI.getDiagnostics()), MainFileName(MainFileName),
146e5dd7070Spatrick OutputFileName(OutputFileName), Ctx(nullptr),
147e5dd7070Spatrick MMap(CI.getPreprocessor().getHeaderSearchInfo().getModuleMap()),
148*12c85518Srobert FS(&CI.getVirtualFileSystem()),
149e5dd7070Spatrick HeaderSearchOpts(CI.getHeaderSearchOpts()),
150e5dd7070Spatrick PreprocessorOpts(CI.getPreprocessorOpts()),
151e5dd7070Spatrick TargetOpts(CI.getTargetOpts()), LangOpts(CI.getLangOpts()),
152e5dd7070Spatrick OS(std::move(OS)), Buffer(std::move(Buffer)) {
153e5dd7070Spatrick // The debug info output isn't affected by CodeModel and
154e5dd7070Spatrick // ThreadModel, but the backend expects them to be nonempty.
155e5dd7070Spatrick CodeGenOpts.CodeModel = "default";
156a9ac8606Spatrick LangOpts.setThreadModel(LangOptions::ThreadModelKind::Single);
157e5dd7070Spatrick CodeGenOpts.DebugTypeExtRefs = true;
158e5dd7070Spatrick // When building a module MainFileName is the name of the modulemap file.
159e5dd7070Spatrick CodeGenOpts.MainFileName =
160e5dd7070Spatrick LangOpts.CurrentModule.empty() ? MainFileName : LangOpts.CurrentModule;
161e5dd7070Spatrick CodeGenOpts.setDebugInfo(codegenoptions::FullDebugInfo);
162e5dd7070Spatrick CodeGenOpts.setDebuggerTuning(CI.getCodeGenOpts().getDebuggerTuning());
163e5dd7070Spatrick CodeGenOpts.DebugPrefixMap =
164e5dd7070Spatrick CI.getInvocation().getCodeGenOpts().DebugPrefixMap;
165*12c85518Srobert CodeGenOpts.DebugStrictDwarf = CI.getCodeGenOpts().DebugStrictDwarf;
166e5dd7070Spatrick }
167e5dd7070Spatrick
168e5dd7070Spatrick ~PCHContainerGenerator() override = default;
169e5dd7070Spatrick
Initialize(ASTContext & Context)170e5dd7070Spatrick void Initialize(ASTContext &Context) override {
171e5dd7070Spatrick assert(!Ctx && "initialized multiple times");
172e5dd7070Spatrick
173e5dd7070Spatrick Ctx = &Context;
174e5dd7070Spatrick VMContext.reset(new llvm::LLVMContext());
175e5dd7070Spatrick M.reset(new llvm::Module(MainFileName, *VMContext));
176a9ac8606Spatrick M->setDataLayout(Ctx->getTargetInfo().getDataLayoutString());
177e5dd7070Spatrick Builder.reset(new CodeGen::CodeGenModule(
178*12c85518Srobert *Ctx, FS, HeaderSearchOpts, PreprocessorOpts, CodeGenOpts, *M, Diags));
179e5dd7070Spatrick
180e5dd7070Spatrick // Prepare CGDebugInfo to emit debug info for a clang module.
181e5dd7070Spatrick auto *DI = Builder->getModuleDebugInfo();
182e5dd7070Spatrick StringRef ModuleName = llvm::sys::path::filename(MainFileName);
183ec727ea7Spatrick DI->setPCHDescriptor(
184ec727ea7Spatrick {ModuleName, "", OutputFileName, ASTFileSignature::createDISentinel()});
185e5dd7070Spatrick DI->setModuleMap(MMap);
186e5dd7070Spatrick }
187e5dd7070Spatrick
HandleTopLevelDecl(DeclGroupRef D)188e5dd7070Spatrick bool HandleTopLevelDecl(DeclGroupRef D) override {
189e5dd7070Spatrick if (Diags.hasErrorOccurred())
190e5dd7070Spatrick return true;
191e5dd7070Spatrick
192e5dd7070Spatrick // Collect debug info for all decls in this group.
193e5dd7070Spatrick for (auto *I : D)
194e5dd7070Spatrick if (!I->isFromASTFile()) {
195e5dd7070Spatrick DebugTypeVisitor DTV(*Builder->getModuleDebugInfo(), *Ctx);
196e5dd7070Spatrick DTV.TraverseDecl(I);
197e5dd7070Spatrick }
198e5dd7070Spatrick return true;
199e5dd7070Spatrick }
200e5dd7070Spatrick
HandleTopLevelDeclInObjCContainer(DeclGroupRef D)201e5dd7070Spatrick void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override {
202e5dd7070Spatrick HandleTopLevelDecl(D);
203e5dd7070Spatrick }
204e5dd7070Spatrick
HandleTagDeclDefinition(TagDecl * D)205e5dd7070Spatrick void HandleTagDeclDefinition(TagDecl *D) override {
206e5dd7070Spatrick if (Diags.hasErrorOccurred())
207e5dd7070Spatrick return;
208e5dd7070Spatrick
209e5dd7070Spatrick if (D->isFromASTFile())
210e5dd7070Spatrick return;
211e5dd7070Spatrick
212e5dd7070Spatrick // Anonymous tag decls are deferred until we are building their declcontext.
213e5dd7070Spatrick if (D->getName().empty())
214e5dd7070Spatrick return;
215e5dd7070Spatrick
216e5dd7070Spatrick // Defer tag decls until their declcontext is complete.
217e5dd7070Spatrick auto *DeclCtx = D->getDeclContext();
218e5dd7070Spatrick while (DeclCtx) {
219e5dd7070Spatrick if (auto *D = dyn_cast<TagDecl>(DeclCtx))
220e5dd7070Spatrick if (!D->isCompleteDefinition())
221e5dd7070Spatrick return;
222e5dd7070Spatrick DeclCtx = DeclCtx->getParent();
223e5dd7070Spatrick }
224e5dd7070Spatrick
225e5dd7070Spatrick DebugTypeVisitor DTV(*Builder->getModuleDebugInfo(), *Ctx);
226e5dd7070Spatrick DTV.TraverseDecl(D);
227e5dd7070Spatrick Builder->UpdateCompletedType(D);
228e5dd7070Spatrick }
229e5dd7070Spatrick
HandleTagDeclRequiredDefinition(const TagDecl * D)230e5dd7070Spatrick void HandleTagDeclRequiredDefinition(const TagDecl *D) override {
231e5dd7070Spatrick if (Diags.hasErrorOccurred())
232e5dd7070Spatrick return;
233e5dd7070Spatrick
234e5dd7070Spatrick if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
235e5dd7070Spatrick Builder->getModuleDebugInfo()->completeRequiredType(RD);
236e5dd7070Spatrick }
237e5dd7070Spatrick
HandleImplicitImportDecl(ImportDecl * D)238e5dd7070Spatrick void HandleImplicitImportDecl(ImportDecl *D) override {
239e5dd7070Spatrick if (!D->getImportedOwningModule())
240e5dd7070Spatrick Builder->getModuleDebugInfo()->EmitImportDecl(*D);
241e5dd7070Spatrick }
242e5dd7070Spatrick
243e5dd7070Spatrick /// Emit a container holding the serialized AST.
HandleTranslationUnit(ASTContext & Ctx)244e5dd7070Spatrick void HandleTranslationUnit(ASTContext &Ctx) override {
245e5dd7070Spatrick assert(M && VMContext && Builder);
246e5dd7070Spatrick // Delete these on function exit.
247e5dd7070Spatrick std::unique_ptr<llvm::LLVMContext> VMContext = std::move(this->VMContext);
248e5dd7070Spatrick std::unique_ptr<llvm::Module> M = std::move(this->M);
249e5dd7070Spatrick std::unique_ptr<CodeGen::CodeGenModule> Builder = std::move(this->Builder);
250e5dd7070Spatrick
251e5dd7070Spatrick if (Diags.hasErrorOccurred())
252e5dd7070Spatrick return;
253e5dd7070Spatrick
254e5dd7070Spatrick M->setTargetTriple(Ctx.getTargetInfo().getTriple().getTriple());
255a9ac8606Spatrick M->setDataLayout(Ctx.getTargetInfo().getDataLayoutString());
256e5dd7070Spatrick
257e5dd7070Spatrick // PCH files don't have a signature field in the control block,
258e5dd7070Spatrick // but LLVM detects DWO CUs by looking for a non-zero DWO id.
259e5dd7070Spatrick // We use the lower 64 bits for debug info.
260a9ac8606Spatrick
261e5dd7070Spatrick uint64_t Signature =
262a9ac8606Spatrick Buffer->Signature ? Buffer->Signature.truncatedValue() : ~1ULL;
263a9ac8606Spatrick
264e5dd7070Spatrick Builder->getModuleDebugInfo()->setDwoId(Signature);
265e5dd7070Spatrick
266e5dd7070Spatrick // Finalize the Builder.
267e5dd7070Spatrick if (Builder)
268e5dd7070Spatrick Builder->Release();
269e5dd7070Spatrick
270e5dd7070Spatrick // Ensure the target exists.
271e5dd7070Spatrick std::string Error;
272e5dd7070Spatrick auto Triple = Ctx.getTargetInfo().getTriple();
273e5dd7070Spatrick if (!llvm::TargetRegistry::lookupTarget(Triple.getTriple(), Error))
274*12c85518Srobert llvm::report_fatal_error(llvm::Twine(Error));
275e5dd7070Spatrick
276e5dd7070Spatrick // Emit the serialized Clang AST into its own section.
277e5dd7070Spatrick assert(Buffer->IsComplete && "serialization did not complete");
278e5dd7070Spatrick auto &SerializedAST = Buffer->Data;
279e5dd7070Spatrick auto Size = SerializedAST.size();
280*12c85518Srobert
281*12c85518Srobert if (Triple.isOSBinFormatWasm()) {
282*12c85518Srobert // Emit __clangast in custom section instead of named data segment
283*12c85518Srobert // to find it while iterating sections.
284*12c85518Srobert // This could be avoided if all data segements (the wasm sense) were
285*12c85518Srobert // represented as their own sections (in the llvm sense).
286*12c85518Srobert // TODO: https://github.com/WebAssembly/tool-conventions/issues/138
287*12c85518Srobert llvm::NamedMDNode *MD =
288*12c85518Srobert M->getOrInsertNamedMetadata("wasm.custom_sections");
289*12c85518Srobert llvm::Metadata *Ops[2] = {
290*12c85518Srobert llvm::MDString::get(*VMContext, "__clangast"),
291*12c85518Srobert llvm::MDString::get(*VMContext,
292*12c85518Srobert StringRef(SerializedAST.data(), Size))};
293*12c85518Srobert auto *NameAndContent = llvm::MDTuple::get(*VMContext, Ops);
294*12c85518Srobert MD->addOperand(NameAndContent);
295*12c85518Srobert } else {
296e5dd7070Spatrick auto Int8Ty = llvm::Type::getInt8Ty(*VMContext);
297e5dd7070Spatrick auto *Ty = llvm::ArrayType::get(Int8Ty, Size);
298e5dd7070Spatrick auto *Data = llvm::ConstantDataArray::getString(
299e5dd7070Spatrick *VMContext, StringRef(SerializedAST.data(), Size),
300e5dd7070Spatrick /*AddNull=*/false);
301e5dd7070Spatrick auto *ASTSym = new llvm::GlobalVariable(
302*12c85518Srobert *M, Ty, /*constant*/ true, llvm::GlobalVariable::InternalLinkage,
303*12c85518Srobert Data, "__clang_ast");
304e5dd7070Spatrick // The on-disk hashtable needs to be aligned.
305e5dd7070Spatrick ASTSym->setAlignment(llvm::Align(8));
306e5dd7070Spatrick
307e5dd7070Spatrick // Mach-O also needs a segment name.
308e5dd7070Spatrick if (Triple.isOSBinFormatMachO())
309e5dd7070Spatrick ASTSym->setSection("__CLANG,__clangast");
310e5dd7070Spatrick // COFF has an eight character length limit.
311e5dd7070Spatrick else if (Triple.isOSBinFormatCOFF())
312e5dd7070Spatrick ASTSym->setSection("clangast");
313e5dd7070Spatrick else
314e5dd7070Spatrick ASTSym->setSection("__clangast");
315*12c85518Srobert }
316e5dd7070Spatrick
317e5dd7070Spatrick LLVM_DEBUG({
318e5dd7070Spatrick // Print the IR for the PCH container to the debug output.
319e5dd7070Spatrick llvm::SmallString<0> Buffer;
320e5dd7070Spatrick clang::EmitBackendOutput(
321e5dd7070Spatrick Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts, LangOpts,
322a9ac8606Spatrick Ctx.getTargetInfo().getDataLayoutString(), M.get(),
323e5dd7070Spatrick BackendAction::Backend_EmitLL,
324e5dd7070Spatrick std::make_unique<llvm::raw_svector_ostream>(Buffer));
325e5dd7070Spatrick llvm::dbgs() << Buffer;
326e5dd7070Spatrick });
327e5dd7070Spatrick
328e5dd7070Spatrick // Use the LLVM backend to emit the pch container.
329e5dd7070Spatrick clang::EmitBackendOutput(Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts,
330a9ac8606Spatrick LangOpts,
331a9ac8606Spatrick Ctx.getTargetInfo().getDataLayoutString(), M.get(),
332a9ac8606Spatrick BackendAction::Backend_EmitObj, std::move(OS));
333e5dd7070Spatrick
334e5dd7070Spatrick // Free the memory for the temporary buffer.
335e5dd7070Spatrick llvm::SmallVector<char, 0> Empty;
336e5dd7070Spatrick SerializedAST = std::move(Empty);
337e5dd7070Spatrick }
338e5dd7070Spatrick };
339e5dd7070Spatrick
340e5dd7070Spatrick } // anonymous namespace
341e5dd7070Spatrick
342e5dd7070Spatrick std::unique_ptr<ASTConsumer>
CreatePCHContainerGenerator(CompilerInstance & CI,const std::string & MainFileName,const std::string & OutputFileName,std::unique_ptr<llvm::raw_pwrite_stream> OS,std::shared_ptr<PCHBuffer> Buffer) const343e5dd7070Spatrick ObjectFilePCHContainerWriter::CreatePCHContainerGenerator(
344e5dd7070Spatrick CompilerInstance &CI, const std::string &MainFileName,
345e5dd7070Spatrick const std::string &OutputFileName,
346e5dd7070Spatrick std::unique_ptr<llvm::raw_pwrite_stream> OS,
347e5dd7070Spatrick std::shared_ptr<PCHBuffer> Buffer) const {
348e5dd7070Spatrick return std::make_unique<PCHContainerGenerator>(
349e5dd7070Spatrick CI, MainFileName, OutputFileName, std::move(OS), Buffer);
350e5dd7070Spatrick }
351e5dd7070Spatrick
352e5dd7070Spatrick StringRef
ExtractPCH(llvm::MemoryBufferRef Buffer) const353e5dd7070Spatrick ObjectFilePCHContainerReader::ExtractPCH(llvm::MemoryBufferRef Buffer) const {
354e5dd7070Spatrick StringRef PCH;
355e5dd7070Spatrick auto OFOrErr = llvm::object::ObjectFile::createObjectFile(Buffer);
356e5dd7070Spatrick if (OFOrErr) {
357e5dd7070Spatrick auto &OF = OFOrErr.get();
358e5dd7070Spatrick bool IsCOFF = isa<llvm::object::COFFObjectFile>(*OF);
359e5dd7070Spatrick // Find the clang AST section in the container.
360e5dd7070Spatrick for (auto &Section : OF->sections()) {
361e5dd7070Spatrick StringRef Name;
362e5dd7070Spatrick if (Expected<StringRef> NameOrErr = Section.getName())
363e5dd7070Spatrick Name = *NameOrErr;
364e5dd7070Spatrick else
365e5dd7070Spatrick consumeError(NameOrErr.takeError());
366e5dd7070Spatrick
367e5dd7070Spatrick if ((!IsCOFF && Name == "__clangast") || (IsCOFF && Name == "clangast")) {
368e5dd7070Spatrick if (Expected<StringRef> E = Section.getContents())
369e5dd7070Spatrick return *E;
370e5dd7070Spatrick else {
371e5dd7070Spatrick handleAllErrors(E.takeError(), [&](const llvm::ErrorInfoBase &EIB) {
372e5dd7070Spatrick EIB.log(llvm::errs());
373e5dd7070Spatrick });
374e5dd7070Spatrick return "";
375e5dd7070Spatrick }
376e5dd7070Spatrick }
377e5dd7070Spatrick }
378e5dd7070Spatrick }
379e5dd7070Spatrick handleAllErrors(OFOrErr.takeError(), [&](const llvm::ErrorInfoBase &EIB) {
380e5dd7070Spatrick if (EIB.convertToErrorCode() ==
381e5dd7070Spatrick llvm::object::object_error::invalid_file_type)
382e5dd7070Spatrick // As a fallback, treat the buffer as a raw AST.
383e5dd7070Spatrick PCH = Buffer.getBuffer();
384e5dd7070Spatrick else
385e5dd7070Spatrick EIB.log(llvm::errs());
386e5dd7070Spatrick });
387e5dd7070Spatrick return PCH;
388e5dd7070Spatrick }
389