//===- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h --------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains support for writing Microsoft CodeView debug info. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_CODEGEN_ASMPRINTER_CODEVIEWDEBUG_H #define LLVM_LIB_CODEGEN_ASMPRINTER_CODEVIEWDEBUG_H #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/DbgEntityHistoryCalculator.h" #include "llvm/CodeGen/DebugHandlerBase.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/IR/DebugLoc.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Compiler.h" #include #include #include #include #include #include #include namespace llvm { struct ClassInfo; class StringRef; class AsmPrinter; class Function; class GlobalVariable; class MCSectionCOFF; class MCStreamer; class MCSymbol; class MachineFunction; /// Collects and handles line tables information in a CodeView format. class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { public: struct LocalVarDef { /// Indicates that variable data is stored in memory relative to the /// specified register. int InMemory : 1; /// Offset of variable data in memory. int DataOffset : 31; /// Non-zero if this is a piece of an aggregate. uint16_t IsSubfield : 1; /// Offset into aggregate. uint16_t StructOffset : 15; /// Register containing the data or the register base of the memory /// location containing the data. uint16_t CVRegister; uint64_t static toOpaqueValue(const LocalVarDef DR) { uint64_t Val = 0; std::memcpy(&Val, &DR, sizeof(Val)); return Val; } LocalVarDef static createFromOpaqueValue(uint64_t Val) { LocalVarDef DR; std::memcpy(&DR, &Val, sizeof(Val)); return DR; } }; static_assert(sizeof(uint64_t) == sizeof(LocalVarDef)); private: MCStreamer &OS; BumpPtrAllocator Allocator; codeview::GlobalTypeTableBuilder TypeTable; /// Whether to emit type record hashes into .debug$H. bool EmitDebugGlobalHashes = false; /// The codeview CPU type used by the translation unit. codeview::CPUType TheCPU; static LocalVarDef createDefRangeMem(uint16_t CVRegister, int Offset); /// Similar to DbgVariable in DwarfDebug, but not dwarf-specific. struct LocalVariable { const DILocalVariable *DIVar = nullptr; MapVector, 1>> DefRanges; bool UseReferenceType = false; std::optional ConstantValue; }; struct CVGlobalVariable { const DIGlobalVariable *DIGV; PointerUnion GVInfo; }; struct InlineSite { SmallVector InlinedLocals; SmallVector ChildSites; const DISubprogram *Inlinee = nullptr; /// The ID of the inline site or function used with .cv_loc. Not a type /// index. unsigned SiteFuncId = 0; }; // Combines information from DILexicalBlock and LexicalScope. struct LexicalBlock { SmallVector Locals; SmallVector Globals; SmallVector Children; const MCSymbol *Begin; const MCSymbol *End; StringRef Name; }; struct JumpTableInfo { codeview::JumpTableEntrySize EntrySize; const MCSymbol *Base; uint64_t BaseOffset; const MCSymbol *Branch; const MCSymbol *Table; size_t TableSize; }; // For each function, store a vector of labels to its instructions, as well as // to the end of the function. struct FunctionInfo { FunctionInfo() = default; // Uncopyable. FunctionInfo(const FunctionInfo &FI) = delete; /// Map from inlined call site to inlined instructions and child inlined /// call sites. Listed in program order. std::unordered_map InlineSites; /// Ordered list of top-level inlined call sites. SmallVector ChildSites; /// Set of all functions directly inlined into this one. SmallSet Inlinees; SmallVector Locals; SmallVector Globals; std::unordered_map LexicalBlocks; // Lexical blocks containing local variables. SmallVector ChildBlocks; std::vector> Annotations; std::vector> HeapAllocSites; std::vector JumpTables; const MCSymbol *Begin = nullptr; const MCSymbol *End = nullptr; unsigned FuncId = 0; unsigned LastFileId = 0; /// Number of bytes allocated in the prologue for all local stack objects. unsigned FrameSize = 0; /// Number of bytes of parameters on the stack. unsigned ParamSize = 0; /// Number of bytes pushed to save CSRs. unsigned CSRSize = 0; /// Adjustment to apply on x86 when using the VFRAME frame pointer. int OffsetAdjustment = 0; /// Two-bit value indicating which register is the designated frame pointer /// register for local variables. Included in S_FRAMEPROC. codeview::EncodedFramePtrReg EncodedLocalFramePtrReg = codeview::EncodedFramePtrReg::None; /// Two-bit value indicating which register is the designated frame pointer /// register for stack parameters. Included in S_FRAMEPROC. codeview::EncodedFramePtrReg EncodedParamFramePtrReg = codeview::EncodedFramePtrReg::None; codeview::FrameProcedureOptions FrameProcOpts; bool HasStackRealignment = false; bool HaveLineInfo = false; bool HasFramePointer = false; }; FunctionInfo *CurFn = nullptr; codeview::SourceLanguage CurrentSourceLanguage = codeview::SourceLanguage::Masm; // This map records the constant offset in DIExpression of the // DIGlobalVariableExpression referencing the DIGlobalVariable. DenseMap CVGlobalVariableOffsets; // Map used to seperate variables according to the lexical scope they belong // in. This is populated by recordLocalVariable() before // collectLexicalBlocks() separates the variables between the FunctionInfo // and LexicalBlocks. DenseMap> ScopeVariables; // Map to separate global variables according to the lexical scope they // belong in. A null local scope represents the global scope. typedef SmallVector GlobalVariableList; DenseMap > ScopeGlobals; // Array of global variables which need to be emitted into a COMDAT section. SmallVector ComdatVariables; // Array of non-COMDAT global variables. SmallVector GlobalVariables; /// List of static const data members to be emitted as S_CONSTANTs. SmallVector StaticConstMembers; /// The set of comdat .debug$S sections that we've seen so far. Each section /// must start with a magic version number that must only be emitted once. /// This set tracks which sections we've already opened. DenseSet ComdatDebugSections; /// Switch to the appropriate .debug$S section for GVSym. If GVSym, the symbol /// of an emitted global value, is in a comdat COFF section, this will switch /// to a new .debug$S section in that comdat. This method ensures that the /// section starts with the magic version number on first use. If GVSym is /// null, uses the main .debug$S section. void switchToDebugSectionForSymbol(const MCSymbol *GVSym); /// The next available function index for use with our .cv_* directives. Not /// to be confused with type indices for LF_FUNC_ID records. unsigned NextFuncId = 0; InlineSite &getInlineSite(const DILocation *InlinedAt, const DISubprogram *Inlinee); codeview::TypeIndex getFuncIdForSubprogram(const DISubprogram *SP); void calculateRanges(LocalVariable &Var, const DbgValueHistoryMap::Entries &Entries); /// Remember some debug info about each function. Keep it in a stable order to /// emit at the end of the TU. MapVector> FnDebugInfo; /// Map from full file path to .cv_file id. Full paths are built from DIFiles /// and are stored in FileToFilepathMap; DenseMap FileIdMap; /// All inlined subprograms in the order they should be emitted. SmallSetVector InlinedSubprograms; /// Map from a pair of DI metadata nodes and its DI type (or scope) that can /// be nullptr, to CodeView type indices. Primarily indexed by /// {DIType*, DIType*} and {DISubprogram*, DIType*}. /// /// The second entry in the key is needed for methods as DISubroutineType /// representing static method type are shared with non-method function type. DenseMap, codeview::TypeIndex> TypeIndices; /// Map from DICompositeType* to complete type index. Non-record types are /// always looked up in the normal TypeIndices map. DenseMap CompleteTypeIndices; /// Complete record types to emit after all active type lowerings are /// finished. SmallVector DeferredCompleteTypes; /// Number of type lowering frames active on the stack. unsigned TypeEmissionLevel = 0; codeview::TypeIndex VBPType; const DISubprogram *CurrentSubprogram = nullptr; // The UDTs we have seen while processing types; each entry is a pair of type // index and type name. std::vector> LocalUDTs; std::vector> GlobalUDTs; using FileToFilepathMapTy = std::map; FileToFilepathMapTy FileToFilepathMap; StringRef getFullFilepath(const DIFile *File); unsigned maybeRecordFile(const DIFile *F); void maybeRecordLocation(const DebugLoc &DL, const MachineFunction *MF); void clear(); void setCurrentSubprogram(const DISubprogram *SP) { CurrentSubprogram = SP; LocalUDTs.clear(); } /// Emit the magic version number at the start of a CodeView type or symbol /// section. Appears at the front of every .debug$S or .debug$T or .debug$P /// section. void emitCodeViewMagicVersion(); void emitTypeInformation(); void emitTypeGlobalHashes(); void emitObjName(); void emitCompilerInformation(); void emitBuildInfo(); void emitInlineeLinesSubsection(); void emitDebugInfoForThunk(const Function *GV, FunctionInfo &FI, const MCSymbol *Fn); void emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI); void emitDebugInfoForRetainedTypes(); void emitDebugInfoForUDTs( const std::vector> &UDTs); void collectDebugInfoForGlobals(); void emitDebugInfoForGlobals(); void emitGlobalVariableList(ArrayRef Globals); void emitConstantSymbolRecord(const DIType *DTy, APSInt &Value, const std::string &QualifiedName); void emitDebugInfoForGlobal(const CVGlobalVariable &CVGV); void emitStaticConstMemberList(); /// Opens a subsection of the given kind in a .debug$S codeview section. /// Returns an end label for use with endCVSubsection when the subsection is /// finished. MCSymbol *beginCVSubsection(codeview::DebugSubsectionKind Kind); void endCVSubsection(MCSymbol *EndLabel); /// Opens a symbol record of the given kind. Returns an end label for use with /// endSymbolRecord. MCSymbol *beginSymbolRecord(codeview::SymbolKind Kind); void endSymbolRecord(MCSymbol *SymEnd); /// Emits an S_END, S_INLINESITE_END, or S_PROC_ID_END record. These records /// are empty, so we emit them with a simpler assembly sequence that doesn't /// involve labels. void emitEndSymbolRecord(codeview::SymbolKind EndKind); void emitInlinedCallSite(const FunctionInfo &FI, const DILocation *InlinedAt, const InlineSite &Site); void emitInlinees(const SmallSet &Inlinees); using InlinedEntity = DbgValueHistoryMap::InlinedEntity; void collectGlobalVariableInfo(); void collectVariableInfo(const DISubprogram *SP); void collectVariableInfoFromMFTable(DenseSet &Processed); // Construct the lexical block tree for a routine, pruning emptpy lexical // scopes, and populate it with local variables. void collectLexicalBlockInfo(SmallVectorImpl &Scopes, SmallVectorImpl &Blocks, SmallVectorImpl &Locals, SmallVectorImpl &Globals); void collectLexicalBlockInfo(LexicalScope &Scope, SmallVectorImpl &ParentBlocks, SmallVectorImpl &ParentLocals, SmallVectorImpl &ParentGlobals); /// Records information about a local variable in the appropriate scope. In /// particular, locals from inlined code live inside the inlining site. void recordLocalVariable(LocalVariable &&Var, const LexicalScope *LS); /// Emits local variables in the appropriate order. void emitLocalVariableList(const FunctionInfo &FI, ArrayRef Locals); /// Emits an S_LOCAL record and its associated defined ranges. void emitLocalVariable(const FunctionInfo &FI, const LocalVariable &Var); /// Emits a sequence of lexical block scopes and their children. void emitLexicalBlockList(ArrayRef Blocks, const FunctionInfo& FI); /// Emit a lexical block scope and its children. void emitLexicalBlock(const LexicalBlock &Block, const FunctionInfo& FI); /// Translates the DIType to codeview if necessary and returns a type index /// for it. codeview::TypeIndex getTypeIndex(const DIType *Ty, const DIType *ClassTy = nullptr); codeview::TypeIndex getTypeIndexForThisPtr(const DIDerivedType *PtrTy, const DISubroutineType *SubroutineTy); codeview::TypeIndex getTypeIndexForReferenceTo(const DIType *Ty); codeview::TypeIndex getMemberFunctionType(const DISubprogram *SP, const DICompositeType *Class); codeview::TypeIndex getScopeIndex(const DIScope *Scope); codeview::TypeIndex getVBPTypeIndex(); void addToUDTs(const DIType *Ty); void addUDTSrcLine(const DIType *Ty, codeview::TypeIndex TI); codeview::TypeIndex lowerType(const DIType *Ty, const DIType *ClassTy); codeview::TypeIndex lowerTypeAlias(const DIDerivedType *Ty); codeview::TypeIndex lowerTypeArray(const DICompositeType *Ty); codeview::TypeIndex lowerTypeString(const DIStringType *Ty); codeview::TypeIndex lowerTypeBasic(const DIBasicType *Ty); codeview::TypeIndex lowerTypePointer( const DIDerivedType *Ty, codeview::PointerOptions PO = codeview::PointerOptions::None); codeview::TypeIndex lowerTypeMemberPointer( const DIDerivedType *Ty, codeview::PointerOptions PO = codeview::PointerOptions::None); codeview::TypeIndex lowerTypeModifier(const DIDerivedType *Ty); codeview::TypeIndex lowerTypeFunction(const DISubroutineType *Ty); codeview::TypeIndex lowerTypeVFTableShape(const DIDerivedType *Ty); codeview::TypeIndex lowerTypeMemberFunction( const DISubroutineType *Ty, const DIType *ClassTy, int ThisAdjustment, bool IsStaticMethod, codeview::FunctionOptions FO = codeview::FunctionOptions::None); codeview::TypeIndex lowerTypeEnum(const DICompositeType *Ty); codeview::TypeIndex lowerTypeClass(const DICompositeType *Ty); codeview::TypeIndex lowerTypeUnion(const DICompositeType *Ty); /// Symbol records should point to complete types, but type records should /// always point to incomplete types to avoid cycles in the type graph. Only /// use this entry point when generating symbol records. The complete and /// incomplete type indices only differ for record types. All other types use /// the same index. codeview::TypeIndex getCompleteTypeIndex(const DIType *Ty); codeview::TypeIndex lowerCompleteTypeClass(const DICompositeType *Ty); codeview::TypeIndex lowerCompleteTypeUnion(const DICompositeType *Ty); struct TypeLoweringScope; void emitDeferredCompleteTypes(); void collectMemberInfo(ClassInfo &Info, const DIDerivedType *DDTy); ClassInfo collectClassInfo(const DICompositeType *Ty); /// Common record member lowering functionality for record types, which are /// structs, classes, and unions. Returns the field list index and the member /// count. std::tuple lowerRecordFieldList(const DICompositeType *Ty); /// Inserts {{Node, ClassTy}, TI} into TypeIndices and checks for duplicates. codeview::TypeIndex recordTypeIndexForDINode(const DINode *Node, codeview::TypeIndex TI, const DIType *ClassTy = nullptr); /// Collect the names of parent scopes, innermost to outermost. Return the /// innermost subprogram scope if present. Ensure that parent type scopes are /// inserted into the type table. const DISubprogram * collectParentScopeNames(const DIScope *Scope, SmallVectorImpl &ParentScopeNames); std::string getFullyQualifiedName(const DIScope *Scope, StringRef Name); std::string getFullyQualifiedName(const DIScope *Scope); unsigned getPointerSizeInBytes(); void discoverJumpTableBranches(const MachineFunction *MF, bool isThumb); void collectDebugInfoForJumpTables(const MachineFunction *MF, bool isThumb); void emitDebugInfoForJumpTables(const FunctionInfo &FI); protected: /// Gather pre-function debug information. void beginFunctionImpl(const MachineFunction *MF) override; /// Gather post-function debug information. void endFunctionImpl(const MachineFunction *) override; /// Check if the current module is in Fortran. bool moduleIsInFortran() { return CurrentSourceLanguage == codeview::SourceLanguage::Fortran; } public: CodeViewDebug(AsmPrinter *AP); void beginModule(Module *M) override; void setSymbolSize(const MCSymbol *, uint64_t) override {} /// Emit the COFF section that holds the line table information. void endModule() override; /// Process beginning of an instruction. void beginInstruction(const MachineInstr *MI) override; }; template <> struct DenseMapInfo { static inline CodeViewDebug::LocalVarDef getEmptyKey() { return CodeViewDebug::LocalVarDef::createFromOpaqueValue(~0ULL); } static inline CodeViewDebug::LocalVarDef getTombstoneKey() { return CodeViewDebug::LocalVarDef::createFromOpaqueValue(~0ULL - 1ULL); } static unsigned getHashValue(const CodeViewDebug::LocalVarDef &DR) { return CodeViewDebug::LocalVarDef::toOpaqueValue(DR) * 37ULL; } static bool isEqual(const CodeViewDebug::LocalVarDef &LHS, const CodeViewDebug::LocalVarDef &RHS) { return CodeViewDebug::LocalVarDef::toOpaqueValue(LHS) == CodeViewDebug::LocalVarDef::toOpaqueValue(RHS); } }; } // end namespace llvm #endif // LLVM_LIB_CODEGEN_ASMPRINTER_CODEVIEWDEBUG_H