Index: include/clang/CodeGen/ModuleBuilder.h =================================================================== --- include/clang/CodeGen/ModuleBuilder.h +++ include/clang/CodeGen/ModuleBuilder.h @@ -35,6 +35,7 @@ namespace CodeGen { class CodeGenModule; + class CGDebugInfo; } /// The primary public interface to the Clang code generator. @@ -65,6 +66,14 @@ /// CodeGenerator after releasing its module. llvm::Module *ReleaseModule(); + /// Return reference to CGDebugInfo place holder. + /// + /// This methods can be called before initializing the CGDebugInfo calss. + /// But the returned value should not be used until after initialization. + /// It is caller responsibility to validate that the place holder was + /// initialized before start using it. + CodeGen::CGDebugInfo *&CodeGenerator::getModuleDebugInfoRef(); + /// Given a mangled name, return a declaration which mangles that way /// which has been added to this code generator via a Handle method. /// Index: lib/CodeGen/CGDebugInfo.h =================================================================== --- lib/CodeGen/CGDebugInfo.h +++ lib/CodeGen/CGDebugInfo.h @@ -412,6 +412,15 @@ void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD); + /// Get macro debug info. + llvm::DIMacro *CreateMacro(llvm::DIMacroFile *Parent, unsigned MType, + SourceLocation LineLoc, StringRef Name, + StringRef Value); + + /// Get temporary macro file debug info. + llvm::DIMacroFile *CreateTempMacroFile(llvm::DIMacroFile *Parent, + SourceLocation LineLoc, + SourceLocation FileLoc); private: /// Emit call to llvm.dbg.declare for a variable declaration. void EmitDeclare(const VarDecl *decl, llvm::Value *AI, Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -2408,6 +2408,22 @@ FullName); } +llvm::DIMacro *CGDebugInfo::CreateMacro(llvm::DIMacroFile *Parent, + unsigned MType, SourceLocation LineLoc, + StringRef Name, StringRef Value) { + unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc); + return DBuilder.createMacro(Parent, Line, MType, Name, Value); +} + +llvm::DIMacroFile *CGDebugInfo::CreateTempMacroFile(llvm::DIMacroFile *Parent, + SourceLocation LineLoc, + SourceLocation FileLoc) { + llvm::DIFile *FName = getOrCreateFile(FileLoc); + unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc); + return DBuilder.createTempMacroFile(Parent, Line, FName, + llvm::DIMacroNodeArray()); +} + static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { Qualifiers Quals; do { Index: lib/CodeGen/CMakeLists.txt =================================================================== --- lib/CodeGen/CMakeLists.txt +++ lib/CodeGen/CMakeLists.txt @@ -77,6 +77,7 @@ CodeGenTypes.cpp CoverageMappingGen.cpp ItaniumCXXABI.cpp + MacroPPCallbacks.cpp MicrosoftCXXABI.cpp ModuleBuilder.cpp ObjectFilePCHContainerOperations.cpp Index: lib/CodeGen/CodeGenAction.cpp =================================================================== --- lib/CodeGen/CodeGenAction.cpp +++ lib/CodeGen/CodeGenAction.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "CoverageMappingGen.h" +#include "MacroPPCallbacks.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" @@ -40,6 +41,11 @@ using namespace llvm; namespace clang { + +namespace CodeGen { +class CGDebugInfo; +} + class BackendConsumer : public ASTConsumer { virtual void anchor(); DiagnosticsEngine &Diags; @@ -98,6 +104,10 @@ I.second.release(); } + CodeGen::CGDebugInfo *&getModuleDebugInfo() { + return Gen->getModuleDebugInfoRef(); + } + void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override { Gen->HandleCXXStaticMemberVarInstantiation(VD); } @@ -812,6 +822,15 @@ CI.getLangOpts(), CI.getFrontendOpts().ShowTimers, InFile, LinkModules, std::move(OS), *VMContext, CoverageInfo)); BEConsumer = Result.get(); + + // Enable generating macro debug info only in FullDebugInfo mode. + if (CI.getCodeGenOpts().getDebugInfo() == codegenoptions::FullDebugInfo) { + std::unique_ptr Callbacks = + llvm::make_unique(BEConsumer->getModuleDebugInfo(), + CI.getPreprocessor()); + CI.getPreprocessor().addPPCallbacks(std::move(Callbacks)); + } + return std::move(Result); } Index: lib/CodeGen/MacroPPCallbacks.h =================================================================== --- lib/CodeGen/MacroPPCallbacks.h +++ lib/CodeGen/MacroPPCallbacks.h @@ -0,0 +1,110 @@ +//===--- MacroPPCallbacks.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines implementation for the macro preprocessors callbacks. +// +//===----------------------------------------------------------------------===// + +#include "clang/Lex/PPCallbacks.h" + +namespace llvm { +class DIMacroFile; +class DIMacroNode; +} +namespace clang { +class Preprocessor; +class MacroInfo; + +namespace CodeGen { +class CGDebugInfo; +} + +class MacroPPCallbacks : public PPCallbacks { + /// A reference pointer to debug info code generator. + CodeGen::CGDebugInfo *&DebugInfo; + + /// Preprocessor. + Preprocessor &PP; + + /// Location of recent included file, used for line number. + SourceLocation LastHashLoc; + + /// Location of main file, used for file info. + SourceLocation MainFileLoc; + + /// Counts current number of command line included files, which was entered + /// and was not exited yet. + int CommandIncludeFiles; + + enum FileScopeStatus { + NoScope, // Scope is not initialized yet. + InitializedScope, // Main file scope is initialized but not set yet. + BuiltinScope, // file scope. + CommandLineScope, // file scope. + CommandLineScopeIncludes, // Included file, from file, scope. + MainFileScope // Main file scope. + }; + FileScopeStatus Status; + + /// Parent contains all entered files that were not exited yet according to + /// the inclusion order. + llvm::SmallVector Scopes; + + /// Get current DIMacroFile scope. + /// \return current DIMacroFile scope or nullptr if there is no such scope. + llvm::DIMacroFile *getCurrentScope(); + + /// Get current line location or invalid location. + /// \param Loc current line location. + /// \return current line location \p `Loc`, or invalid location if it's in a + /// skipped file scope. + SourceLocation getCorrectLocation(SourceLocation Loc); + + /// Use the passed preprocessor to calculate the macro name and value from + /// the given macro info and identifier info. + /// + /// \param II Identifier info, used to get the Macro name. + /// \param MI Macro info, used to get the Macro argumets and values. + /// \param PP Preprocessor. + /// \param [out] Name Place holder for returned macro name and arguments. + /// \param [out] Value Place holder for returned macro value. + static void calculatMacroDefinition(const IdentifierInfo &II, + const MacroInfo &MI, Preprocessor &PP, + raw_ostream &Name, raw_ostream &Value); + +public: + MacroPPCallbacks(CodeGen::CGDebugInfo *&DI, Preprocessor &PP); + + /// Callback invoked whenever a source file is entered or exited. + /// + /// \param Loc Indicates the new location. + /// \param PrevFID the file that was exited if \p Reason is ExitFile. + void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID = FileID()) override; + + /// Callback invoked whenever a directive (#xxx) is processed. + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, + const Module *Imported) override; + + /// Hook called whenever a macro definition is seen. + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override; + + /// Hook called whenever a macro \#undef is seen. + /// + /// MD is released immediately following this callback. + void MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD) override; +}; + +} // end namespace clang Index: lib/CodeGen/MacroPPCallbacks.cpp =================================================================== --- lib/CodeGen/MacroPPCallbacks.cpp +++ lib/CodeGen/MacroPPCallbacks.cpp @@ -0,0 +1,189 @@ +//===--- MacroPPCallbacks.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains implementation for the macro preprocessors callbacks. +// +//===----------------------------------------------------------------------===// + +#include "MacroPPCallbacks.h" +#include "CGDebugInfo.h" +#include "clang/Parse/Parser.h" + +using namespace clang; + +void MacroPPCallbacks::calculatMacroDefinition(const IdentifierInfo &II, + const MacroInfo &MI, + Preprocessor &PP, + raw_ostream &Name, + raw_ostream &Value) { + Name << II.getName(); + + if (MI.isFunctionLike()) { + Name << '('; + if (!MI.arg_empty()) { + MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end(); + for (; AI + 1 != E; ++AI) { + Name << (*AI)->getName(); + Name << ','; + } + + // Last argument. + if ((*AI)->getName() == "__VA_ARGS__") + Name << "..."; + else + Name << (*AI)->getName(); + } + + if (MI.isGNUVarargs()) + Name << "..."; // #define foo(x...) + + Name << ')'; + } + + SmallString<128> SpellingBuffer; + bool First = true; + for (const auto &T : MI.tokens()) { + if (!First && T.hasLeadingSpace()) + Value << ' '; + + Value << PP.getSpelling(T, SpellingBuffer); + First = false; + } +} + +MacroPPCallbacks::MacroPPCallbacks(CodeGen::CGDebugInfo *&DI, Preprocessor &PP) + : DebugInfo(DI), PP(PP), Status(NoScope), + // CommandIncludeFiles counts the number of currently processed files, + // which are included from command line. Initialized to zero. + CommandIncludeFiles(0) {} + +llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() { + switch (Status) { + default: + return nullptr; + case CommandLineScopeIncludes: + case MainFileScope: + return Scopes.back(); + } +} + +SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) { + switch (Status) { + default: + break; + case CommandLineScopeIncludes: + if (!CommandIncludeFiles) + break; + // Fall though! + case MainFileScope: + return Loc; + } + // While parsing skipped files, location of macros is invalid. + // Invalid location represents line zero. + return SourceLocation(); +} + +void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) { + // Only care about enter file or exit file changes. + if (Reason != EnterFile && Reason != ExitFile) + return; + + bool CreateMainFile = false; + bool CreateMacroFile = false; + bool PopScope = false; + SourceLocation LineLoc = getCorrectLocation(LastHashLoc); + switch (Status) { + case NoScope: + MainFileLoc = Loc; + Status = InitializedScope; + break; + case InitializedScope: + Status = BuiltinScope; + break; + case BuiltinScope: + Status = CommandLineScope; + break; + case CommandLineScope: + Status = CommandLineScopeIncludes; + CreateMainFile = true; + break; + case CommandLineScopeIncludes: + if (Reason == EnterFile) { + CommandIncludeFiles++; + CreateMacroFile = true; + } else if (Reason == ExitFile) { + if (!CommandIncludeFiles) + Status = MainFileScope; + else { + CommandIncludeFiles--; + PopScope = true; + } + } + break; + case MainFileScope: + if (Reason == EnterFile) + CreateMacroFile = true; + else if (Reason == ExitFile) + PopScope = true; + // No need to change status, already in the final status. + break; + } + + if (CreateMainFile) + Scopes.push_back( + DebugInfo->CreateTempMacroFile(nullptr, LineLoc, MainFileLoc)); + if (CreateMacroFile) + Scopes.push_back( + DebugInfo->CreateTempMacroFile(getCurrentScope(), LineLoc, Loc)); + if (PopScope) + Scopes.pop_back(); +} + +void MacroPPCallbacks::InclusionDirective( + SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, + bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, const Module *Imported) { + // Only care about "include" directives. + if (!IncludeTok.is(tok::identifier)) + return; + auto PPKeywordID = IncludeTok.getIdentifierInfo()->getPPKeywordID(); + switch (PPKeywordID) { + default: + return; + case tok::pp_include: + case tok::pp_include_next: + case tok::pp___include_macros: + break; + } + + // Record the line location of the current included file. + LastHashLoc = HashLoc; +} + +void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) { + IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); + SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); + std::string NameBuffer, ValueBuffer; + llvm::raw_string_ostream Name(NameBuffer); + llvm::raw_string_ostream Value(ValueBuffer); + calculatMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value); + DebugInfo->CreateMacro(getCurrentScope(), llvm::dwarf::DW_MACINFO_define, + location, Name.str(), Value.str()); +} + +void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok, + const MacroDefinition &MD) { + IdentifierInfo *Id = MacroNameTok.getIdentifierInfo(); + SourceLocation location = getCorrectLocation(MacroNameTok.getLocation()); + DebugInfo->CreateMacro(getCurrentScope(), llvm::dwarf::DW_MACINFO_undef, + location, Id->getName(), ""); +} Index: lib/CodeGen/ModuleBuilder.cpp =================================================================== --- lib/CodeGen/ModuleBuilder.cpp +++ lib/CodeGen/ModuleBuilder.cpp @@ -65,6 +65,7 @@ private: SmallVector DeferredInlineMethodDefinitions; + CGDebugInfo *DebugInfoRef; public: CodeGeneratorImpl(DiagnosticsEngine &diags, llvm::StringRef ModuleName, @@ -74,7 +75,8 @@ CoverageSourceInfo *CoverageInfo = nullptr) : Diags(diags), Ctx(nullptr), HeaderSearchOpts(HSO), PreprocessorOpts(PPO), CodeGenOpts(CGO), HandlingTopLevelDecls(0), - CoverageInfo(CoverageInfo), M(new llvm::Module(ModuleName, C)) { + CoverageInfo(CoverageInfo), M(new llvm::Module(ModuleName, C)), + DebugInfoRef(nullptr) { C.setDiscardValueNames(CGO.DiscardValueNames); } @@ -92,6 +94,10 @@ return M.get(); } + CGDebugInfo *&getModuleDebugInfoRef() { + return DebugInfoRef; + } + llvm::Module *ReleaseModule() { return M.release(); } @@ -124,6 +130,9 @@ PreprocessorOpts, CodeGenOpts, *M, Diags, CoverageInfo)); + // Initialize the place holder for the CGDebugInfo. + DebugInfoRef = Builder->getModuleDebugInfo(); + for (auto &&Lib : CodeGenOpts.DependentLibraries) Builder->AddDependentLib(Lib); for (auto &&Opt : CodeGenOpts.LinkerOptions) @@ -299,6 +308,10 @@ return static_cast(this)->ReleaseModule(); } +CGDebugInfo *&CodeGenerator::getModuleDebugInfoRef() { + return static_cast(this)->getModuleDebugInfoRef(); +} + const Decl *CodeGenerator::GetDeclForMangledName(llvm::StringRef name) { return static_cast(this)->GetDeclForMangledName(name); } Index: test/CodeGen/debug-info-global-constant.c =================================================================== --- test/CodeGen/debug-info-global-constant.c +++ test/CodeGen/debug-info-global-constant.c @@ -7,7 +7,7 @@ // CHECK: @i = internal constant i32 1, align 4, !dbg ![[I:[0-9]+]] // CHECK: ![[I]] = !DIGlobalVariableExpression(var: ![[VAR:.*]], expr: ![[EXPR:[0-9]+]]) // CHECK: ![[VAR]] = distinct !DIGlobalVariable(name: "i", -// CHECK: !DICompileUnit({{.*}}globals: ![[GLOBALS:[0-9]+]]) +// CHECK: !DICompileUnit({{.*}}globals: ![[GLOBALS:[0-9]+]] // CHECK: ![[GLOBALS]] = !{![[I]]} // CHECK: ![[EXPR]] = !DIExpression(DW_OP_constu, 1, DW_OP_stack_value) static const int i = 1;