Index: include/llvm/CodeGen/AsmPrinter.h =================================================================== --- include/llvm/CodeGen/AsmPrinter.h +++ include/llvm/CodeGen/AsmPrinter.h @@ -22,6 +22,7 @@ #include "llvm/Support/ErrorHandling.h" namespace llvm { + class AsmDebug; class BlockAddress; class GCStrategy; class Constant; @@ -44,7 +45,6 @@ class MCStreamer; class MCSymbol; class MDNode; - class DwarfDebug; class DwarfException; class Mangler; class TargetLoweringObjectFile; @@ -107,8 +107,8 @@ /// function. MachineLoopInfo *LI; - /// DD - If the target supports dwarf debug info, this pointer is non-null. - DwarfDebug *DD; + /// DI - If the target supports debug info, this pointer is non-null. + AsmDebug *DI; /// DE - If the target supports dwarf exception info, this pointer is /// non-null. Index: include/llvm/DebugInfo.h =================================================================== --- include/llvm/DebugInfo.h +++ include/llvm/DebugInfo.h @@ -479,17 +479,21 @@ unsigned getLineNumber() const { return getUnsignedField(7); } DICompositeType getType() const { return getFieldAs(8); } - /// getReturnTypeName - Subprogram return types are encoded either as - /// DIType or as DICompositeType. - StringRef getReturnTypeName() const { + /// \brief Subprogram return types are encoded either as DIType or + /// as DICompositeType. + DIType getReturnType() const { DICompositeType DCT(getFieldAs(8)); if (DCT.Verify()) { DIArray A = DCT.getTypeArray(); - DIType T(A.getElement(0)); - return T.getName(); + return DIType(A.getElement(0)); } - DIType T(getFieldAs(8)); - return T.getName(); + return DIType(getFieldAs(8)); + } + + /// \brief Subprogram return types are encoded either as DIType or + /// as DICompositeType. + StringRef getReturnTypeName() const { + return getReturnType().getName(); } /// isLocalToUnit - Return true if this subprogram is local to the current Index: include/llvm/MC/MCAsmInfo.h =================================================================== --- include/llvm/MC/MCAsmInfo.h +++ include/llvm/MC/MCAsmInfo.h @@ -28,6 +28,10 @@ class MCSymbol; class MCContext; + namespace DebugInformation { + enum DebugInformationType { None, Dwarf, CodeView }; + } + namespace ExceptionHandling { enum ExceptionsType { None, DwarfCFI, SjLj, ARM, Win64 }; } @@ -301,9 +305,9 @@ /// HasLEB128 - True if target asm supports leb128 directives. bool HasLEB128; // Defaults to false. - /// SupportsDebugInformation - True if target supports emission of debugging - /// information. - bool SupportsDebugInformation; // Defaults to false. + /// DebugInformationType - Contains type of debug information to emit. + /// Defaults to None. + DebugInformation::DebugInformationType DebugInformationType; /// SupportsExceptionHandling - True if target supports exception handling. ExceptionHandling::ExceptionsType ExceptionsType; // Defaults to None @@ -521,7 +525,10 @@ return HasLEB128; } bool doesSupportDebugInformation() const { - return SupportsDebugInformation; + return DebugInformationType != DebugInformation::None; + } + DebugInformation::DebugInformationType getDebugInformationType() const { + return DebugInformationType; } bool doesSupportExceptionHandling() const { return ExceptionsType != ExceptionHandling::None; Index: include/llvm/MC/MCObjectFileInfo.h =================================================================== --- include/llvm/MC/MCObjectFileInfo.h +++ include/llvm/MC/MCObjectFileInfo.h @@ -174,6 +174,8 @@ const MCSection *DrectveSection; const MCSection *PDataSection; const MCSection *XDataSection; + const MCSection *DebugSSection; + const MCSection *DebugTSection; public: void InitMCObjectFileInfo(StringRef TT, Reloc::Model RM, CodeModel::Model CM, @@ -311,6 +313,8 @@ const MCSection *getDrectveSection() const { return DrectveSection; } const MCSection *getPDataSection() const { return PDataSection; } const MCSection *getXDataSection() const { return XDataSection; } + const MCSection *getDebugSSection() const { return DebugSSection; } + const MCSection *getDebugTSection() const { return DebugTSection; } const MCSection *getEHFrameSection() { if (!EHFrameSection) Index: include/llvm/Support/CodeView.h =================================================================== --- /dev/null +++ include/llvm/Support/CodeView.h @@ -0,0 +1,613 @@ +//===------ llvm/Support/CodeView.h --- CodeView Constants ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file contains constants and structures used for implementing +/// CodeView debug information on Windows platforms. For more information, see +/// Visual C++ 5.0 Symbolic Debug Information Specification, Revision 5. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_CODEVIEW_H +#define LLVM_SUPPORT_CODEVIEW_H + +#include "llvm/Support/DataTypes.h" + +namespace llvm { +namespace CodeView { + +#pragma pack(push) +#pragma pack(1) + +/* + * The .debug$S segments contains the symbol information. It starts with the + * CodeView version (0x0004, 4 bytes). + * Then follows a sequence of subsections. General layout of a subsection is: + * + * +-----------------+ 4-byte aligned + * | type (4 bytes) | + * +-----------------+ + * | length (4bytes) | does not include type, length and padding + * +-----------------+ + * | ... | + * +-----------------+ + * | padding (0x00) | only if required, repeated until next + * +-----------------+ address is 4-byte aligned + * + * Currently are 4 subsections defined. + * + * Type = 0x000f1. Contains the symbol information. + * See CodeViewSymbol below. + * + * Type = 0x000f2. Line numbers for section. + * +-------------------------------------------------------------+ + * | start offset in section (SECREL to section start) (4 bytes) | + * +-------------------------------------------------------------+ + * | section index (SECTION to section start) (2 bytes) | + * +-------------------------------------------------------------+ + * | pad/align (0) (2 bytes) | + * +-------------------------------------------------------------+ + * | section length covered by line number info (4 bytes) | + * +-------------------------------------------------------------+ + * | offset of source file in source file info table (4 bytes) | + * +-------------------------------------------------------------+ + * | number of line number pairs (4 bytes) | + * +-------------------------------------------------------------+ + * | number of bytes of line number pairs + 12 (4 bytes) | + * +-------------------------------------------------------------+ + * + * followed by repeated sequence of + * + * +-------------------------------------------------------------+ + * | offset in section (4bytes) | + * +-------------------------------------------------------------+ + * | line number (4bytes) | + * +-------------------------------------------------------------+ + + followed by pairs of: + 4 bytes - offset in section + 4 bytes - line number; if high bit is set, + end of statement/breakpointable (?) - e.g. lines containing + just labels should have line numbers + + * + * Type = 0x000f3. Source filename string table. + 1 byte - 0 (0th filename) + 0-terminated filename strings, 1 for each source file + * + * + * Type = 0x000f4. Info about source files. + for each source file: + 4 bytes - offset of filename in source filename string table + {2 bytes - checksum type/length? (0x0110) + 16 bytes - MD5 checksum of source file} OR + {2 bytes - no checksum (0)} + 2 bytes - 0 (padding?) + */ + +typedef unsigned long CV_uoff32_t; +typedef long CV_off32_t; +typedef unsigned short CV_uoff16_t; +typedef short CV_off16_t; +typedef unsigned short CV_typ_t; + +enum { + CV_SIGNATURE_C7 = 0x0001, + CV_SIGNATURE_C8 = 0x0004 +}; + +enum { + Symbol_Section = 0x00f1, + Line_Number_Section = 0x00f2, + Sourcefile_Table_Section = 0x00f3, + Sourcefile_Info_Section = 0x00f4 +}; + +enum CodeViewSymbolId { + S_COMPILE_V1 = 0x0001, // Compile flags symbol + S_REGISTER_V1 = 0x0002, // Register variable + S_CONSTANT_V1 = 0x0003, // Constant symbol + S_UDT_V1 = 0x0004, // User-defined Type + S_SSEARCH_V1 = 0x0005, // Start search + S_END_V1 = 0x0006, // End block, procedure, with, or thunk + S_SKIP_V1 = 0x0007, // Skip - Reserve symbol space + S_CVRESERVE_V1 = 0x0008, // Reserved for CodeView internal use + S_OBJNAME_V1 = 0x0009, // Specify name of object file + S_ENDARG_V1 = 0x000a, // Specify end of arguments in function symbols + S_COBOLUDT_V1 = 0x000b, // Microfocus COBOL user-defined type + S_MANYREG_V1 = 0x000c, // Many register symbol + S_RETURN_V1 = 0x000d, // Function return description + S_ENTRYTHIS_V1 = 0x000e, // Description of this pointer at entry + + /* 16 bit entry omitted */ + + S_BPREL_V1 = 0x0200, // BP relative 16:32 + S_LDATA_V1 = 0x0201, // Local data 16:32 + S_GDATA_V1 = 0x0202, // Global data 16:32 + S_PUB_V1 = 0x0203, // Public symbol 16:32 + S_LPROC_V1 = 0x0204, // Local procedure start 16:32 + S_GPROC_V1 = 0x0205, // Global procedure start 16:32 + S_THUNK_V1 = 0x0206, // Thunk start 16:32 + S_BLOCK_V1 = 0x0207, // Block start 16:32 + S_WITH_V1 = 0x0208, // With start 16:32 + S_LABEL_V1 = 0x0209, // Label 16:32 + S_VFTPATH_V1 = 0x020b, // Virtual function table path descriptor 16:32 + S_REGREL_V1 = 0x020c, // 16:32 offset relative to arbitrary register + S_LTHREAD_V1 = 0x020d, // Local Thread Storage data + S_GTHREAD_V1 = 0x020e, // Global Thread Storage data + + S_LPROCMIPS_V1 = 0x0300, // Local procedure start MIPS + S_GPROCMIPS_V1 = 0x0301, // Global procedure start MIPS + + S_PROCREF = 0x0400, // Reference to a procedure + S_DATAREF = 0x0401, // Reference to data + S_ALIGN = 0x0402, // Page align symbols + S_LPROCREF_V1 = 0x0403, + + S_REGISTER_V2 = 0x1001, // Register variable + S_CONSTANT_V2 = 0x1002, // Constant symbol + S_UDT_V2 = 0x1003, // User-defined type + S_COBOLUDT_V2 = 0x1004, // Microfocus COBOL user-defined type + S_MANYREG_V2 = 0x1005, // Many register symbol + S_BPREL_V2 = 0x1006, // BP relative 16:32 + S_LDATA_V2 = 0x1007, // Local data 16:32 + S_GDATA_V2 = 0x1008, // Global data 16:32 + S_PUB_V2 = 0x1009, // Public symbol 16:32 + S_LPROC_V2 = 0x100a, // Local procedure start 16:32 + S_GPROC_V2 = 0x100b, // Global procedure start 16:32 + S_VFTTABLE_V2 = 0x100c, // Virtual function table path descriptor 16:32 + S_REGREL_V2 = 0x100d, // 16:32 offset relative to arbitrary register + S_LTHREAD_V2 = 0x100e, // Local Thread Storage data + S_GTHREAD_V2 = 0x100f, // Global Thread Storage data + S_LPROCMIPS_V2 = 0x1010, // Local procedure start MIPS + S_GPROCMIPS_V2 = 0x1011, // Global procedure start MIPS + S_FRAMEINFO_V2 = 0x1012, + S_COMPILAND_V2 = 0x1013, + + S_OBJNAME_V2 = 0x1101, + S_THUNK_V3 = 0x1102, + S_BLOCK_V3 = 0x1103, + S_LABEL_V3 = 0x1105, + S_REGISTER_V3 = 0x1106, + S_CONSTANT_V3 = 0x1107, + S_UDT_V3 = 0x1108, + S_BPREL_V3 = 0x110B, + S_LDATA_V3 = 0x110C, + S_GDATA_V3 = 0x110D, + S_PUB_V3 = 0x110E, + S_LPROC_V3 = 0x110F, + S_GPROC_V3 = 0x1110, + S_REGREL_V3 = 0x1111, + S_LTHREAD_V3 = 0x1112, + S_GTHREAD_V3 = 0x1113, + S_MSTOOL_V3 = 0x1116, + S_PUB_FUNC1_V3 = 0x1125, + S_PUB_FUNC2_V3 = 0x1127, + S_SECTINFO_V3 = 0x1136, + S_SUBSECTINFO_V3 = 0x1137, + S_ENTRYPOINT_V3 = 0x1138, + S_SECUCOOKIE_V3 = 0x113A, + S_MSTOOLINFO_V3 = 0x113C, + S_MSTOOLENV_V3 = 0x113D +}; + +union CodeViewSymbol { + struct { + uint16_t Length; + uint16_t SymbolId; + } Generic; + struct { + uint16_t Length; + uint16_t SymbolId; // == S_OBJNAME_V2 + uint32_t Signature; + char Objname[1]; + } Objname_V2; +}; + + +/* +struct CodeViewLineNumer { + uint32_t Offset; + uint32_t LinenumStart; + uint32_t DeltaLineEnd; + uint32_t FStatement; +}; + +typedef struct CodeViewColumn { + uint16_t offColumnStart; + uint16_t offColumnEnd; +}; +*/ + +/* + * The .debug$T segments contains the type information. It starts with the + * CodeView version (0x0004, 4 bytes). Then follows a sequence of type + * records. A type record has the following structure: + * + * +----------------+-------------------------------+ + * | type (2 bytes) | type string (0 or more bytes) | + * +----------------+-------------------------------+ + * + * A type string is a repeated sequence of leaf structures: + * + * +----------------+------------------------+ + * | leaf (2 bytes) | data (0 or more bytes) | (possible repeated) + * +----------------+------------------------+ + * + * + */ + +enum { + LF_MODIFIER_V1 = 0x0001, + LF_POINTER_V1 = 0x0002, + LF_ARRAY_V1 = 0x0003, + LF_CLASS_V1 = 0x0004, + LF_STRUCTURE_V1 = 0x0005, + LF_UNION_V1 = 0x0006, + LF_ENUM_V1 = 0x0007, + LF_PROCEDURE_V1 = 0x0008, + LF_MFUNCTION_V1 = 0x0009, + LF_VTSHAPE_V1 = 0x000a, + LF_COBOL0_V1 = 0x000b, + LF_COBOL1_V1 = 0x000c, + LF_BARRAY_V1 = 0x000d, + LF_LABEL_V1 = 0x000e, + LF_NULL_V1 = 0x000f, + LF_NOTTRAN_V1 = 0x0010, + LF_DIMARRAY_V1 = 0x0011, + LF_VFTPATH_V1 = 0x0012, + LF_PRECOMP_V1 = 0x0013, + LF_ENDPRECOMP_V1 = 0x0014, + LF_OEM_V1 = 0x0015, + LF_TYPESERVER_V1 = 0x0016, + + LF_MODIFIER_V2 = 0x1001, /* variants with new 32-bit type indices (V2) */ + LF_POINTER_V2 = 0x1002, + LF_ARRAY_V2 = 0x1003, + LF_CLASS_V2 = 0x1004, + LF_STRUCTURE_V2 = 0x1005, + LF_UNION_V2 = 0x1006, + LF_ENUM_V2 = 0x1007, + LF_PROCEDURE_V2 = 0x1008, + LF_MFUNCTION_V2 = 0x1009, + LF_COBOL0_V2 = 0x100a, + LF_BARRAY_V2 = 0x100b, + LF_DIMARRAY_V2 = 0x100c, + LF_VFTPATH_V2 = 0x100d, + LF_PRECOMP_V2 = 0x100e, + LF_OEM_V2 = 0x100f, + + LF_SKIP_V1 = 0x0200, + LF_ARGLIST_V1 = 0x0201, + LF_DEFARG_V1 = 0x0202, + LF_LIST_V1 = 0x0203, + LF_FIELDLIST_V1 = 0x0204, + LF_DERIVED_V1 = 0x0205, + LF_BITFIELD_V1 = 0x0206, + LF_METHODLIST_V1 = 0x0207, + LF_DIMCONU_V1 = 0x0208, + LF_DIMCONLU_V1 = 0x0209, + LF_DIMVARU_V1 = 0x020a, + LF_DIMVARLU_V1 = 0x020b, + LF_REFSYM_V1 = 0x020c, + + LF_SKIP_V2 = 0x1200, /* variants with new 32-bit type indices (V2) */ + LF_ARGLIST_V2 = 0x1201, + LF_DEFARG_V2 = 0x1202, + LF_FIELDLIST_V2 = 0x1203, + LF_DERIVED_V2 = 0x1204, + LF_BITFIELD_V2 = 0x1205, + LF_METHODLIST_V2 = 0x1206, + LF_DIMCONU_V2 = 0x1207, + LF_DIMCONLU_V2 = 0x1208, + LF_DIMVARU_V2 = 0x1209, + LF_DIMVARLU_V2 = 0x120a, + + /* Field lists */ + LF_BCLASS_V1 = 0x0400, + LF_VBCLASS_V1 = 0x0401, + LF_IVBCLASS_V1 = 0x0402, + LF_ENUMERATE_V1 = 0x0403, + LF_FRIENDFCN_V1 = 0x0404, + LF_INDEX_V1 = 0x0405, + LF_MEMBER_V1 = 0x0406, + LF_STMEMBER_V1 = 0x0407, + LF_METHOD_V1 = 0x0408, + LF_NESTTYPE_V1 = 0x0409, + LF_VFUNCTAB_V1 = 0x040a, + LF_FRIENDCLS_V1 = 0x040b, + LF_ONEMETHOD_V1 = 0x040c, + LF_VFUNCOFF_V1 = 0x040d, + LF_NESTTYPEEX_V1 = 0x040e, + LF_MEMBERMODIFY_V1 = 0x040f, + + LF_BCLASS_V2 = 0x1400, /* variants with new 32-bit type indices (V2) */ + LF_VBCLASS_V2 = 0x1401, + LF_IVBCLASS_V2 = 0x1402, + LF_FRIENDFCN_V2 = 0x1403, + LF_INDEX_V2 = 0x1404, + LF_MEMBER_V2 = 0x1405, + LF_STMEMBER_V2 = 0x1406, + LF_METHOD_V2 = 0x1407, + LF_NESTTYPE_V2 = 0x1408, + LF_VFUNCTAB_V2 = 0x1409, + LF_FRIENDCLS_V2 = 0x140a, + LF_ONEMETHOD_V2 = 0x140b, + LF_VFUNCOFF_V2 = 0x140c, + LF_NESTTYPEEX_V2 = 0x140d, + + LF_ENUMERATE_V3 = 0x1502, + LF_ARRAY_V3 = 0x1503, + LF_CLASS_V3 = 0x1504, + LF_STRUCTURE_V3 = 0x1505, + LF_UNION_V3 = 0x1506, + LF_ENUM_V3 = 0x1507, + LF_MEMBER_V3 = 0x150d, + LF_STMEMBER_V3 = 0x150e, + LF_METHOD_V3 = 0x150f, + LF_NESTTYPE_V3 = 0x1510, + LF_ONEMETHOD_V3 = 0x1511, + + LF_NUMERIC = 0x8000, /* numeric leaf types */ + LF_CHAR = 0x8000, + LF_SHORT = 0x8001, + LF_USHORT = 0x8002, + LF_LONG = 0x8003, + LF_ULONG = 0x8004, + LF_REAL32 = 0x8005, + LF_REAL64 = 0x8006, + LF_REAL80 = 0x8007, + LF_REAL128 = 0x8008, + LF_QUADWORD = 0x8009, + LF_UQUADWORD = 0x800a, + LF_REAL48 = 0x800b, + LF_COMPLEX32 = 0x800c, + LF_COMPLEX64 = 0x800d, + LF_COMPLEX80 = 0x800e, + LF_COMPLEX128 = 0x800f, + LF_VARSTRING = 0x8010 +}; + +enum { + CV_FIRST_NONPRIM = 0x1000 +}; + +enum { + T_Size_Mask = 0x0007, + T_Mode_Mask = 0x0700, + T_ModeShift = 8, + T_Type_Mask = 0x00f0, + T_Type_Shift = 4, + + // types + T_Special = 0x00, + T_Signed_integral_value = 0x01, + T_Unsigned_integral_value = 0x02, + T_Boolean = 0x03, + T_Real = 0x04, + T_Complex = 0x05, + T_Special2 = 0x06, + T_Real_int_value = 0x07, + // 0x08 - 0x0e Reserved + // 0x0f Reserved for debugger expression evaluator + + // Size + // Type = special + T_No_type = 0x00, + T_Absolute_symbol = 0x01, + T_Segment = 0x02, + T_Void = 0x03, + T_Basic_8_byte_currency_value = 0x04, + T_Near_Basic_string = 0x05, + T_Far_Basic_string = 0x06, + T_Untranslated_type_from_previous_Microsoft_symbol_formats = 0x07, + + /* bit patterns for the portion of a built-in type number */ + T_Near_Ptr_Bits = 0x0100, + T_Far_Ptr_Bits = 0x0200, + T_Huge_Ptr_Bits = 0x0300, + T_Near32_Ptr_Bits = 0x0400, + T_Far32_Ptr_Bits = 0x0500, + T_Near64_Ptr_Bits = 0x0600, +}; + + +enum { + // Values for pointer records + // Pointers can be one of the following types + CV_PTR_NEAR = 0x00, /* near pointer */ + CV_PTR_FAR = 0x01, /* far pointer */ + CV_PTR_HUGE = 0x02, /* huge pointer */ + CV_PTR_BASE_SEG = 0x03, /* based on segment */ + CV_PTR_BASE_VAL = 0x04, /* based on value of base */ + CV_PTR_BASE_SEGVAL = 0x05, /* based on segment value of base */ + CV_PTR_BASE_ADDR = 0x06, /* based on address of base */ + CV_PTR_BASE_SEGADDR = 0x07, /* based on segment address of base */ + CV_PTR_BASE_TYPE = 0x08, /* based on type */ + CV_PTR_BASE_SELF = 0x09, /* based on self */ + CV_PTR_NEAR32 = 0x0a, /* 16:32 near pointer */ + CV_PTR_FAR32 = 0x0b, /* 16:32 far pointer */ + CV_PTR_64 = 0x0c, /* 64 bit pointer */ + CV_PTR_UNUSEDPTR = 0x0d, /* first unused pointer type */ + + + + + + + + + // Values for function call type + CV_CALL_NEAR_C = 0x00, // near right to left push, caller pops stack + CV_CALL_FAR_C = 0x01, // far right to left push, caller pops stack + CV_CALL_NEAR_PASCAL = 0x02, // near left to right push, callee pops stack + CV_CALL_FAR_PASCAL = 0x03, // far left to right push, callee pops stack + CV_CALL_NEAR_FAST = 0x04, // near left to right push with regs, callee pops stack + CV_CALL_FAR_FAST = 0x05, // far left to right push with regs, callee pops stack + CV_CALL_SKIPPED = 0x06, // skipped (unused) call index + CV_CALL_NEAR_STD = 0x07, // near standard call + CV_CALL_FAR_STD = 0x08, // far standard call + CV_CALL_NEAR_SYS = 0x09, // near sys call + CV_CALL_FAR_SYS = 0x0a, // far sys call + CV_CALL_THISCALL = 0x0b, // this call (this passed in register) + CV_CALL_MIPSCALL = 0x0c, // Mips call + CV_CALL_GENERIC = 0x0d, // Generic call sequence + CV_CALL_ALPHACALL = 0x0e, // Alpha call + CV_CALL_PPCCALL = 0x0f, // PPC call + CV_CALL_RESERVED = 0x10, // first unused call enumeration + + +}; + +// enumeration for LF_MODIFIER values + + +struct CV_modifier_t { + unsigned short MOD_const :1; + unsigned short MOD_volatile :1; + unsigned short MOD_unaligned :1; + unsigned short MOD_unused :13; +}; + + +// bit field structure describing class/struct/union/enum properties + +struct CV_prop_t { + unsigned short packed :1; // true if structure is packed + unsigned short ctor :1; // true if constructors or destructors present + unsigned short ovlops :1; // true if overloaded operators present + unsigned short isnested :1; // true if this is a nested class + unsigned short cnested :1; // true if this class contains nested types + unsigned short opassign :1; // true if overloaded assignment (=) + unsigned short opcast :1; // true if casting methods + unsigned short fwdref :1; // true if forward reference (incomplete defn) + unsigned short scoped :1; // scoped definition + unsigned short reserved :7; +}; + + + + +// class field attribute + +struct CV_fldattr_t { + unsigned short access :2; // access protection CV_access_t + unsigned short mprop :3; // method properties CV_methodprop_t + unsigned short pseudo :1; // compiler generated fcn and does not exist + unsigned short noinherit :1; // true if class cannot be inherited + unsigned short noconstruct :1; // true if class cannot be constructed + unsigned short unused :8; // unused +}; + +// Argument list leaf +struct Arglist_V2 { + uint16_t leaf; // LF_ARGLIST_V2 + uint32_t argcount; // count of number of indices in list + uint32_t indices[1]; // type indices of argument types +}; +struct Procedure_V1 { + uint16_t leaf; // LF_PROCEDURE_V1 + uint16_t rvtype; // type index of return value + uint8_t calltype; // calling convention (CV_call_t) + uint8_t reserved; // reserved for future use + uint16_t parmcount; // number of parameters + uint16_t arglist; // type index of argument list +}; +struct Procedure_V2 { + uint16_t leaf; // LF_PROCEDURE_V2 + uint32_t rvtype; // type index of return value + uint8_t calltype; // calling convention (CV_call_t) + uint8_t reserved; // reserved for future use + uint16_t parmcount; // number of parameters + uint32_t arglist; // type index of argument list +}; +struct Struct_v3 { + uint16_t leaf; // LF_STRUCT_V3 + uint16_t n_element; + uint16_t property; + uint16_t fieldlist; + uint16_t derived; + uint16_t vshape; + uint32_t structlen; /* numeric leaf */ + char name[1]; +} ; +struct Modifier_v2 +{ + uint16_t leaf; // LF_MODIFIER_V2 + uint32_t type; + uint16_t attribute; + + bool isConst() { return attribute & 0x01; } + void setConst(bool b) + { if (b) attribute |= 0x01; else attribute &= ~0x01; } + bool isVolatile() { return attribute & 0x02; } + void setVolatile(bool b) + { if (b) attribute |= 0x02; else attribute &= ~0x02; } + bool isUnaligned() { return attribute & 0x04; } + void setUnaligned(bool b) + { if (b) attribute |= 0x04; else attribute &= ~0x04; } +}; + +// Pointer lead +struct Pointer_v2 +{ + uint16_t leaf; // LF_POINTER_V2 + uint32_t type; + uint32_t attribute; +}; + +// Field list leaf +// This is the header leaf for a complex list of class and structure subfields. +struct FieldList { + uint16_t leaf; // LF_FIELDLIST + char data[]; // field list sub lists +}; + + +// subfield record for non-static data members +struct Member_v2 { + uint16_t leaf; // LF_MEMBER_V2 + CV_typ_t index; // index of type record for field + CV_fldattr_t attr; // attribute mask + unsigned char offset[]; // variable length offset of field followed + // by length prefixed name of field +}; + + +union Leaf { + struct { + uint16_t Leaf; + uint8_t Data; + } Generic; + struct { + unsigned short leaf; // LF_MODIFIER + CV_modifier_t attr; // modifier attribute modifier_t + CV_typ_t type; // modified type + } Modifier; + struct { + unsigned short leaf; // LF_ENUM + unsigned short count; // count of number of elements in class + CV_typ_t utype; // underlying type of the enum + CV_typ_t field; // type index of LF_FIELD descriptor list + CV_prop_t property; // property attribute field + unsigned char Name[1]; // length prefixed name of enum + } Enum; + Arglist_V2 Arglist_V2; + Modifier_v2 Modifier_v2; + Pointer_v2 Pointer_v2; + Procedure_V1 Procedure_V1; + Procedure_V2 Procedure_V2; +}; + +#pragma pack(pop) + +} // End of namespace CodeView +} // End of namespace llvm + +#endif Index: lib/CodeGen/AsmPrinter/AsmDebug.h =================================================================== --- /dev/null +++ lib/CodeGen/AsmPrinter/AsmDebug.h @@ -0,0 +1,73 @@ +//===----- llvm/CodeGen/AsmDebug.cpp - Asm Debug Framework ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file contains the support interface for writing debug +/// information into asm files. +/// +//===----------------------------------------------------------------------===// + +#ifndef CODEGEN_ASMPRINTER_ASMDEBUG_H +#define CODEGEN_ASMPRINTER_ASMDEBUG_H + +#include "llvm/DebugInfo.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/LexicalScopes.h" +#include "llvm/MC/MachineLocation.h" + +namespace llvm { + +class MachineFrameInfo; +class MachineModuleInfo; +class MachineOperand; +class MCAsmInfo; + +/// \brief Collects and handles debug information. +class AsmDebug { +protected: + // Target of debug information emission. + AsmPrinter *Asm; + + // Collected machine module information. + MachineModuleInfo *MMI; + +public: + //===--------------------------------------------------------------------===// + // Main entry points. + // + AsmDebug(AsmPrinter *A) : Asm(A), MMI(Asm->MMI) {} + virtual ~AsmDebug() {} + + /// \brief Collect debug info from named mdnodes such as llvm.dbg.enum + /// and llvm.dbg.ty + virtual void collectInfoFromNamedMDNodes(const Module *M) = 0; + + /// \brief Emit all debug information sections that should come prior to the + /// content. + virtual void beginModule() = 0; + + /// \brief Emit all debug information sections that should come after the + /// content. + virtual void endModule() = 0; + + /// \brief Gather pre-function debug information. + virtual void beginFunction(const MachineFunction *MF) = 0; + + /// \brief Gather and emit post-function debug information. + virtual void endFunction(const MachineFunction *MF) = 0; + + /// \brief Process beginning of an instruction. + virtual void beginInstruction(const MachineInstr *MI) = 0; + + /// \brief Process end of an instruction. + virtual void endInstruction(const MachineInstr *MI) = 0; +}; +} // End of namespace llvm + +#endif Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -13,6 +13,8 @@ #define DEBUG_TYPE "asm-printer" #include "llvm/CodeGen/AsmPrinter.h" +#include "AsmDebug.h" +#include "CodeViewDebug.h" #include "DwarfDebug.h" #include "DwarfException.h" #include "llvm/ADT/SmallString.h" @@ -96,14 +98,14 @@ OutContext(Streamer.getContext()), OutStreamer(Streamer), LastMI(0), LastFn(0), Counter(~0U), SetCounter(0) { - DD = 0; DE = 0; MMI = 0; LI = 0; + DI = 0; DE = 0; MMI = 0; LI = 0; CurrentFnSym = CurrentFnSymForSize = 0; GCMetadataPrinters = 0; VerboseAsm = Streamer.isVerboseAsm(); } AsmPrinter::~AsmPrinter() { - assert(DD == 0 && DE == 0 && "Debug/EH info didn't get finalized"); + assert(DI == 0 && DE == 0 && "Debug/EH info didn't get finalized"); if (GCMetadataPrinters != 0) { gcp_map_type &GCMap = getGCMap(GCMetadataPrinters); @@ -183,9 +185,16 @@ OutStreamer.AddBlankLine(); } - if (MAI->doesSupportDebugInformation()) - DD = new DwarfDebug(this, &M); - + switch (MAI->getDebugInformationType()) { + case DebugInformation::None: + break; + case DebugInformation::Dwarf: + DI = new DwarfDebug(this, &M); + break; + case DebugInformation::CodeView: + DI = new CodeViewDebug(this, &M); + break; + } switch (MAI->getExceptionHandlingType()) { case ExceptionHandling::None: return false; @@ -465,9 +474,9 @@ NamedRegionTimer T(EHTimerName, DWARFGroupName, TimePassesIsEnabled); DE->BeginFunction(MF); } - if (DD) { + if (DI) { NamedRegionTimer T(DbgTimerName, DWARFGroupName, TimePassesIsEnabled); - DD->beginFunction(MF); + DI->beginFunction(MF); } } @@ -648,7 +657,7 @@ // Emit target-specific gunk before the function body. EmitFunctionBodyStart(); - bool ShouldPrintDebugScopes = DD && MMI->hasDebugInfo(); + bool ShouldPrintDebugScopes = DI && MMI->hasDebugInfo(); // Print out code for the function. bool HasAnyRealCode = false; @@ -670,7 +679,7 @@ if (ShouldPrintDebugScopes) { NamedRegionTimer T(DbgTimerName, DWARFGroupName, TimePassesIsEnabled); - DD->beginInstruction(II); + DI->beginInstruction(II); } if (isVerbose()) @@ -710,7 +719,7 @@ if (ShouldPrintDebugScopes) { NamedRegionTimer T(DbgTimerName, DWARFGroupName, TimePassesIsEnabled); - DD->endInstruction(II); + DI->endInstruction(II); } } } @@ -767,9 +776,9 @@ } // Emit post-function debug information. - if (DD) { + if (DI) { NamedRegionTimer T(DbgTimerName, DWARFGroupName, TimePassesIsEnabled); - DD->endFunction(MF); + DI->endFunction(MF); } if (DE) { NamedRegionTimer T(EHTimerName, DWARFGroupName, TimePassesIsEnabled); @@ -871,12 +880,12 @@ } delete DE; DE = 0; } - if (DD) { + if (DI) { { NamedRegionTimer T(DbgTimerName, DWARFGroupName, TimePassesIsEnabled); - DD->endModule(); + DI->endModule(); } - delete DD; DD = 0; + delete DI; DI = 0; } // If the target wants to know about weak references, print them all. Index: lib/CodeGen/AsmPrinter/CMakeLists.txt =================================================================== --- lib/CodeGen/AsmPrinter/CMakeLists.txt +++ lib/CodeGen/AsmPrinter/CMakeLists.txt @@ -3,6 +3,7 @@ AsmPrinter.cpp AsmPrinterDwarf.cpp AsmPrinterInlineAsm.cpp + CodeViewDebug.cpp DIE.cpp DwarfAccelTable.cpp DwarfCFIException.cpp Index: lib/CodeGen/AsmPrinter/CodeViewDebug.h =================================================================== --- /dev/null +++ lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -0,0 +1,130 @@ +//=== llvm/CodeGen/CodeViewDebug.cpp - CodeView Debug Framework -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file contains support for writing codeview debug info into +/// asm files. +/// +//===----------------------------------------------------------------------===// + +#ifndef CODEGEN_ASMPRINTER_CODEVIEWDEBUG_H +#define CODEGEN_ASMPRINTER_CODEVIEWDEBUG_H + +#include "AsmDebug.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/LexicalScopes.h" +#include "llvm/DebugInfo.h" +#include "llvm/MC/MachineLocation.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/CodeView.h" +#include "llvm/Support/DebugLoc.h" +#include +#include + +namespace llvm { + +class MachineFrameInfo; +class MachineModuleInfo; +class MachineOperand; +class MCAsmInfo; + +// A single type records +struct LeafRecord { + static LeafRecord *create(uint16_t LeafType, uint32_t Length) { + void *Rec = new uint8_t[Length]; + return new (Rec) LeafRecord(LeafType, Length); + } + + LeafRecord(uint16_t LeafType, uint32_t Length) + : Length(Length) + { + Leaf.Generic.Leaf = LeafType; + } + + uint32_t Length; // Overall Length + union CodeView::Leaf Leaf; +}; + +class TypeStringManager { + typedef std::vector LeafVector; + + LeafVector TypesString; + uint32_t NextIndex; + +public: + TypeStringManager() : NextIndex(0), TypesString(LeafVector()) {} + + // Add a new leaf record, returns index + uint16_t add(LeafRecord *Record); + uint32_t size(); + void emit(AsmPrinter *Asm); + uint16_t toReservedType(const DIBasicType &Type); + uint32_t toTypeIdx(const DIType &Type); + uint32_t parameterToTypeIdx(const DIArray &Vars); + uint32_t procedureToTypeIdx(const DISubprogram &Proc); +}; + +struct Sourcefile { + std::string Filename; + uint32_t Offset; + + Sourcefile(std::string FName, uint32_t Ofs) + : Filename(FName), Offset(Ofs) + {} +}; + +class CodeViewDebug : public AsmDebug { + TypeStringManager TypeString; + + void emitSourcefileTable(std::vector Srcfiles); + void emitSourcefileInfo(std::vector Srcfiles); + void emitPadding(uint32_t Length); + void emitStringZ(const std::string &Str); + +public: + //===--------------------------------------------------------------------===// + // Main entry points. + // + CodeViewDebug(AsmPrinter *A, Module *M); + ~CodeViewDebug(); + + /// collectInfoFromNamedMDNodes - Collect debug info from named mdnodes such + /// as llvm.dbg.enum and llvm.dbg.ty + void collectInfoFromNamedMDNodes(const Module *M); + + /// beginModule - Emit all Dwarf sections that should come prior to the + /// content. + void beginModule(); + + /// endModule - Emit all Dwarf sections that should come after the content. + /// + void endModule(); + + /// beginFunction - Gather pre-function debug information. Assumes being + /// emitted immediately after the function entry point. + void beginFunction(const MachineFunction *MF); + + /// endFunction - Gather and emit post-function debug information. + /// + void endFunction(const MachineFunction *MF); + + /// beginInstruction - Process beginning of an instruction. + void beginInstruction(const MachineInstr *MI); + + /// endInstruction - Prcess end of an instruction. + void endInstruction(const MachineInstr *MI); +}; +} // End of namespace llvm + +#endif Index: lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- /dev/null +++ lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -0,0 +1,549 @@ +//=== llvm/CodeGen/CodeViewDebug.cpp - CodeView Debug Framework -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file contains support for writing codeview debug info into +/// asm files. +/// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "codeviewdebug" +#include "CodeViewDebug.h" +#include "llvm/Constants.h" +#include "llvm/DebugInfo.h" +#include "llvm/DIBuilder.h" +#include "llvm/Module.h" +#include "llvm/Instructions.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/DataLayout.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ValueHandle.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/Path.h" +#include +#include +using namespace llvm; + +namespace { + const char *CodeViewGroupName = "CodeView Emission"; + const char *DbgTimerName = "CodeView Debug Writer"; +} // end anonymous namespace + +static void emit(AsmPrinter *Asm, const CodeView::Modifier_v2 &Leaf) { + assert(Leaf.leaf == CodeView::LF_MODIFIER_V2 && "Unexpected leaf type"); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Leaf type LF_MODIFIER_V2"); + Asm->EmitInt16(Leaf.leaf); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Type index"); + Asm->EmitInt32(Leaf.type); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Attribute"); + Asm->EmitInt16(Leaf.attribute); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Padding"); + Asm->EmitInt16(0xf1f2); +} + +static void emit(AsmPrinter *Asm, const CodeView::Pointer_v2 &Leaf) { + assert(Leaf.leaf == CodeView::LF_POINTER_V2 && "Unexpected leaf type"); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Leaf type LF_POINTER_V2"); + Asm->EmitInt16(Leaf.leaf); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Type index"); + Asm->EmitInt32(Leaf.type); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Attribute"); + Asm->EmitInt32(Leaf.attribute); +} + +static void emit(AsmPrinter *Asm, const CodeView::Arglist_V2 &Leaf) { + assert(Leaf.leaf == CodeView::LF_ARGLIST_V2 && "Unexpected leaf type"); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Leaf type LF_ARGLIST_V2"); + Asm->EmitInt16(Leaf.leaf); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Number of type indices"); + Asm->EmitInt32(Leaf.argcount); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Type indices"); + for (uint32_t I = 0, E = Leaf.argcount; I < E; ++I) { + Asm->EmitInt32(Leaf.indices[I]); + } +} + +static void emit(AsmPrinter *Asm, const CodeView::Procedure_V2 &Leaf) { + assert(Leaf.leaf == CodeView::LF_PROCEDURE_V2 && "Unexpected leaf type"); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Leaf type LF_PROCEDURE_V2"); + Asm->EmitInt16(Leaf.leaf); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Type index of return value"); + Asm->EmitInt32(Leaf.rvtype); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Calling convention"); + Asm->EmitInt8(Leaf.calltype); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Reserved"); + Asm->EmitInt8(Leaf.reserved); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Number of parameters"); + Asm->EmitInt16(Leaf.parmcount); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Type index of parameter list"); + Asm->EmitInt32(Leaf.arglist); +} + +// Add a new leaf record, returns index +uint16_t TypeStringManager::add(LeafRecord *Record) { + uint16_t idx = CodeView::CV_FIRST_NONPRIM + NextIndex; + TypesString.push_back(Record); + ++NextIndex; + return idx; +} + +uint32_t TypeStringManager::size() { + uint64_t Size = 0; + for (LeafVector::const_iterator I = TypesString.cbegin(), + E = TypesString.cend(); + I != E; + ++I) { + LeafRecord *Rec = *I; + Size += (2 /*Size of Leaf Type*/ + Rec->Length); + } + assert(Size <= UINT32_MAX && "Type string is oversized"); + return static_cast(Size); +} + +// Emit the records +void TypeStringManager::emit(AsmPrinter *Asm) { + for (LeafVector::const_iterator I = TypesString.cbegin(), + E = TypesString.cend(); + I != E; + ++I) { + LeafRecord *Rec = *I; + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Length"); + assert(Rec->Length <= UINT16_MAX); + Asm->EmitInt16(Rec->Length); + switch (Rec->Leaf.Generic.Leaf) { + default: llvm_unreachable("Unimplemented leaf type"); + case CodeView::LF_ARGLIST_V2: ::emit(Asm, Rec->Leaf.Arglist_V2); break; + case CodeView::LF_MODIFIER_V2: ::emit(Asm, Rec->Leaf.Modifier_v2); break; + case CodeView::LF_POINTER_V2: ::emit(Asm, Rec->Leaf.Pointer_v2); break; + case CodeView::LF_PROCEDURE_V2: ::emit(Asm, Rec->Leaf.Procedure_V2); break; + } + } +} + +uint16_t TypeStringManager::toReservedType(const DIBasicType &type) { + enum { + SV = CodeView::T_Signed_integral_value << CodeView::T_Type_Shift, + UV = CodeView::T_Unsigned_integral_value << CodeView::T_Type_Shift, + BV = CodeView::T_Boolean << CodeView::T_Type_Shift, + RV = CodeView::T_Real << CodeView::T_Type_Shift, + RiV = CodeView::T_Real_int_value << CodeView::T_Type_Shift, + + }; + uint16_t Res = 0U; + // Encode size + switch (type.getEncoding()) + { + case dwarf::DW_ATE_boolean: + case dwarf::DW_ATE_signed: + case dwarf::DW_ATE_signed_char: + case dwarf::DW_ATE_unsigned: + case dwarf::DW_ATE_unsigned_char: + case dwarf::DW_ATE_UTF: + switch (type.getSizeInBits()) { + default: llvm_unreachable("wrong bit size"); + case 8: Res |= 0; break; + case 16: Res |= 1; break; + case 32: Res |= 2; break; + case 64: Res |= 3; break; + } + break; + case dwarf::DW_ATE_float: + case dwarf::DW_ATE_complex_float: + case dwarf::DW_ATE_imaginary_float: + switch (type.getSizeInBits()) { + default: llvm_unreachable("wrong bit size"); + case 32: Res |= 0; break; + case 64: Res |= 1; break; + case 80: Res |= 2; break; + case 128: Res |= 3; break; + case 48: Res |= 4; break; + } + break; + } + // Encode type + switch (type.getEncoding()) + { + case dwarf::DW_ATE_address: + break; + case dwarf::DW_ATE_boolean: + Res |= CodeView::T_Boolean << CodeView::T_Type_Shift; + break; + case dwarf::DW_ATE_complex_float: + Res |= CodeView::T_Complex << CodeView::T_Type_Shift; + break; + case dwarf::DW_ATE_float: + Res |= CodeView::T_Real << CodeView::T_Type_Shift; + break; + case dwarf::DW_ATE_signed: + Res |= CodeView::T_Signed_integral_value << CodeView::T_Type_Shift; + break; + case dwarf::DW_ATE_signed_char: + break; + case dwarf::DW_ATE_unsigned: + Res |= CodeView::T_Unsigned_integral_value << CodeView::T_Type_Shift; + break; + case dwarf::DW_ATE_unsigned_char: + break; + case dwarf::DW_ATE_imaginary_float: + case dwarf::DW_ATE_packed_decimal: + case dwarf::DW_ATE_numeric_string: + case dwarf::DW_ATE_edited: + case dwarf::DW_ATE_signed_fixed: + case dwarf::DW_ATE_unsigned_fixed: + case dwarf::DW_ATE_decimal_float: + case dwarf::DW_ATE_UTF: + case dwarf::DW_ATE_lo_user: + case dwarf::DW_ATE_hi_user: + llvm_unreachable("Not yet implemented."); + break; + } + assert(Res < CodeView::CV_FIRST_NONPRIM && + "Primitive type index not lower than CV_FIRST_NONPRIM"); + return Res; +} + +uint32_t TypeStringManager::toTypeIdx(const DIType &Type) { + outs() << "toTypeIdx: tag = " << Type.getTag() << "\n"; + uint32_t Res = 0; + if (Type.isBasicType()) { + return toReservedType(DIBasicType(Type)); + } + else if (Type.isCompositeType()) { + outs() << "CompositeType\n"; + Type.print(outs()); outs() << "\n"; outs().flush(); + DICompositeType dct(Type); + outs().flush(); + } + else if (Type.isDerivedType()) { + DIDerivedType DDT(Type); + uint32_t BaseIdx = toTypeIdx(DDT.getTypeDerivedFrom()); + if (BaseIdx < CodeView::CV_FIRST_NONPRIM && + !(BaseIdx & CodeView::T_Mode_Mask) && + DDT.getTag() == dwarf::DW_TAG_pointer_type) { + Res = BaseIdx | CodeView::T_Near64_Ptr_Bits; // FIXME: 32bit + outs() << "Modifying base type\n"; + } + else if (DDT.getTag() == dwarf::DW_TAG_const_type || + DDT.getTag() == dwarf::DW_TAG_volatile_type) { + LeafRecord *Rec = LeafRecord::create(CodeView::LF_MODIFIER_V2, + sizeof(CodeView::Modifier_v2)); + Rec->Leaf.Modifier_v2.type = BaseIdx; + Rec->Leaf.Modifier_v2.attribute = 0; + if (DDT.getTag() == dwarf::DW_TAG_const_type) + Rec->Leaf.Modifier_v2.setConst(true); + if (DDT.getTag() == dwarf::DW_TAG_volatile_type) + Rec->Leaf.Modifier_v2.setVolatile(true); + Res = add(Rec); + outs() << "Adding modifier const: " << Rec->Leaf.Modifier_v2.isConst() + << " volatile: " << Rec->Leaf.Modifier_v2.isVolatile() << "\n"; + } + else if (DDT.getTag() == dwarf::DW_TAG_pointer_type) { + LeafRecord *Rec = LeafRecord::create(CodeView::LF_POINTER_V2, + sizeof(CodeView::Pointer_v2)); + Rec->Leaf.Pointer_v2.type = BaseIdx; + Rec->Leaf.Pointer_v2.attribute = 12; // 64 bit pointer + outs() << "Adding incomplete pointer type\n"; + Res = add(Rec); + } + else { + outs() << "Missing support for something else\n"; + LeafRecord *Rec = LeafRecord::create(CodeView::LF_MODIFIER_V2, + sizeof(CodeView::Modifier_v2)); + Rec->Leaf.Modifier_v2.type = BaseIdx; + Rec->Leaf.Modifier_v2.attribute = 0; // FIXME + Res = add(Rec); + } + } + else { + outs() << "Type not implemented: "; Type.print(outs()); outs() << "\n"; outs().flush(); + //llvm_unreachable("Not yet implemented."); + } + return Res; +} + +uint32_t TypeStringManager::parameterToTypeIdx(const DIArray &Vars) { + LeafRecord *Rec = LeafRecord::create(CodeView::LF_ARGLIST_V2, + sizeof(CodeView::Arglist_V2) + + ((Vars.getNumElements()-1) + * sizeof(uint32_t))); + Rec->Leaf.Arglist_V2.argcount = Vars.getNumElements(); + uint32_t *Data = reinterpret_cast(&Rec->Leaf.Arglist_V2.indices); + for (unsigned I = 0, E = Vars.getNumElements(); I != E; ++I) { + DIVariable DV(Vars.getElement(I)); + *Data++ = toTypeIdx(DV.getType()); + } + return add(Rec); +} + +uint32_t TypeStringManager::procedureToTypeIdx(const DISubprogram &Proc) { + LeafRecord *Rec = LeafRecord::create(CodeView::LF_PROCEDURE_V2, + sizeof(CodeView::Procedure_V2)); + Rec->Leaf.Procedure_V2.rvtype = toTypeIdx(DIType(Proc.getReturnType())); + Rec->Leaf.Procedure_V2.calltype = CodeView::CV_CALL_NEAR_PASCAL; + Rec->Leaf.Procedure_V2.reserved = 0; + Rec->Leaf.Procedure_V2.parmcount = Proc.getVariables().getNumElements(); + Rec->Leaf.Procedure_V2.arglist = parameterToTypeIdx(Proc.getVariables()); + return add(Rec); +} + +CodeViewDebug::CodeViewDebug(AsmPrinter *A, Module *M) + : AsmDebug(A), TypeString(TypeStringManager()) { + { + NamedRegionTimer T(DbgTimerName, CodeViewGroupName, TimePassesIsEnabled); + beginModule(); + } +} + +CodeViewDebug::~CodeViewDebug() { +} + +/// collectInfoFromNamedMDNodes - Collect debug info from named mdnodes such +/// as llvm.dbg.enum and llvm.dbg.ty +void CodeViewDebug::collectInfoFromNamedMDNodes(const Module *M) { + if (NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.sp")) + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { + const MDNode *N = NMD->getOperand(i); + //if (CompileUnit *CU = CUMap.lookup(DISubprogram(N).getCompileUnit())) + // constructSubprogramDIE(CU, N); + } + + if (NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.gv")) + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { + const MDNode *N = NMD->getOperand(i); + //if (CompileUnit *CU = CUMap.lookup(DIGlobalVariable(N).getCompileUnit())) + // CU->createGlobalVariableDIE(N); + } + + if (NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.enum")) + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { + DIType Ty(NMD->getOperand(i)); + //if (CompileUnit *CU = CUMap.lookup(Ty.getCompileUnit())) + // CU->getOrCreateTypeDIE(Ty); + } + + if (NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.ty")) + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { + DIType Ty(NMD->getOperand(i)); + //if (CompileUnit *CU = CUMap.lookup(Ty.getCompileUnit())) + // CU->getOrCreateTypeDIE(Ty); + } +} + +/// beginModule - Emit all Dwarf sections that should come prior to the +/// content. Create global DIEs and emit initial debug info sections. +/// This is invoked by the target AsmPrinter. +void CodeViewDebug::beginModule() { + // Gather source modules. + std::vector Srcfiles; + + const Module *M = MMI->getModule(); + + // If module has named metadata anchors then use them, otherwise scan the + // module using debug info finder to collect debug info. + NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); + if (CU_Nodes) { + Srcfiles.reserve(CU_Nodes->getNumOperands()); + for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { + DICompileUnit CUNode(CU_Nodes->getOperand(i)); + + // FIXME: + // - create the type records from the metadata (includes type indices used in symbols) + // - create mapping MDNode -> type record / type index + { + DIArray SPs = CUNode.getSubprograms(); + for (unsigned i = 0, e = SPs.getNumElements(); i != e; ++i) { + DISubprogram sub(SPs.getElement(i)); + TypeString.procedureToTypeIdx(sub); + } + } + + sys::Path AbsolutePath(CUNode.getDirectory()); + AbsolutePath.appendComponent(CUNode.getFilename()); + uint32_t ofs = 1; + if (!Srcfiles.empty()) { + Sourcefile& prev = Srcfiles[Srcfiles.size()-1]; + ofs = prev.Offset + prev.Filename.length() + 1; + } + Srcfiles.push_back(Sourcefile(AbsolutePath.str(), ofs)); + } + } //else if (!collectLegacyDebugInfo(M)) + //return; + + // Emit .debug$S section + Asm->OutStreamer.SwitchSection( + Asm->getObjFileLowering().getDebugSSection()); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("CodeView Version"); + Asm->EmitInt32(CodeView::CV_SIGNATURE_C8); + // FIXME: emit S_OBJNAME_V2 symbol + // FIXME: emit tool info symbol + if (!Srcfiles.empty()) { + emitSourcefileTable(Srcfiles); + emitSourcefileInfo(Srcfiles); + } +} + +/// endModule - Emit all type information. +/// +void CodeViewDebug::endModule() { + // Emit type information for the module + + // Emit .debug$T section + Asm->OutStreamer.SwitchSection( + Asm->getObjFileLowering().getDebugTSection()); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("CodeView Version"); + Asm->EmitInt32(CodeView::CV_SIGNATURE_C8); + TypeString.emit(Asm); +} + +/// beginInstruction - Process beginning of an instruction. +void CodeViewDebug::beginInstruction(const MachineInstr *MI) { +} + +/// endInstruction - Process end of an instruction. +void CodeViewDebug::endInstruction(const MachineInstr *MI) { +} + +/// beginFunction - Gather pre-function debug information. Assumes being +/// emitted immediately after the function entry point. +void CodeViewDebug::beginFunction(const MachineFunction *MF) { + MCSymbol* FunctionBeginSym = Asm->GetTempSymbol("func_begin", + Asm->getFunctionNumber()); + // Assumes in correct section after the entry point. + Asm->OutStreamer.EmitLabel(FunctionBeginSym); + + //MF-> + + // Record function type + // Length, leaf, data, leaf, data, .... + // Record symbol data +} + +/// endFunction - Gather and emit post-function debug information. +/// +void CodeViewDebug::endFunction(const MachineFunction *MF) { + // Emit symbol information for the function + + // Emit .debug$S section + Asm->OutStreamer.SwitchSection( + Asm->getObjFileLowering().getDebugSSection()); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("CodeView Version"); + Asm->EmitInt32(CodeView::CV_SIGNATURE_C8); +} + +//===----------------------------------------------------------------------===// +// Emit Methods +//===----------------------------------------------------------------------===// + +void CodeViewDebug::emitSourcefileTable(std::vector Srcfiles) { + // Calculate length + uint32_t length = 1; + for (std::vector::const_iterator I = Srcfiles.begin(), + E = Srcfiles.end(); + I != E; ++I) { + length += (*I).Filename.size() + 1; + } + + // Emit + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Sourcefile string table"); + Asm->EmitInt32(CodeView::Sourcefile_Table_Section); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Length of data"); + Asm->EmitInt32(length); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("0th filename"); + Asm->EmitInt8(0); + + for (std::vector::const_iterator I = Srcfiles.begin(), + E = Srcfiles.end(); + I != E; ++I) { + const std::string& Filename = (*I).Filename; + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Filename"); + emitStringZ(Filename); + } + emitPadding(length); +} + +void CodeViewDebug::emitSourcefileInfo(std::vector Srcfiles) { + // Emit + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Sourcefile information"); + Asm->EmitInt32(CodeView::Sourcefile_Info_Section); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Length of data"); + Asm->EmitInt32(Srcfiles.size() * 8); + + for (std::vector::const_iterator I = Srcfiles.begin(), + E = Srcfiles.end(); + I != E; ++I) { + Sourcefile t = *I; + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Offset into Sourcefile string table"); + Asm->EmitInt32(t.Offset); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Checksum"); + Asm->EmitInt16(0); + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Padding"); + Asm->EmitInt16(0); + } +} + +void CodeViewDebug::emitStringZ(const std::string &Str) { + Asm->OutStreamer.EmitBytes(StringRef(Str.c_str(), Str.size()+1), + 0/*addrspace*/); +} + +void CodeViewDebug::emitPadding(uint32_t Length) { + if (Length % 4) { + static const char Zero[4] = { 0, 0, 0, 0 }; + + if (Asm->isVerbose()) + Asm->OutStreamer.AddComment("Padding"); + Asm->OutStreamer.EmitBytes(StringRef(Zero, 4-(Length%4)), 0/*addrspace*/); + } +} \ No newline at end of file Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -14,6 +14,7 @@ #ifndef CODEGEN_ASMPRINTER_DWARFDEBUG_H__ #define CODEGEN_ASMPRINTER_DWARFDEBUG_H__ +#include "AsmDebug.h" #include "DIE.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" @@ -189,12 +190,7 @@ }; /// \brief Collects and handles dwarf debug information. -class DwarfDebug { - // Target of Dwarf emission. - AsmPrinter *Asm; - - // Collected machine module information. - MachineModuleInfo *MMI; +class DwarfDebug : public AsmDebug { // All DIEValues are allocated through this allocator. BumpPtrAllocator DIEValueAllocator; Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -153,7 +153,7 @@ } // end llvm namespace DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) - : Asm(A), MMI(Asm->MMI), FirstCU(0), FissionCU(0), + : AsmDebug(A), FirstCU(0), FissionCU(0), AbbreviationsSet(InitAbbreviationsSetSize), SourceIdMap(DIEValueAllocator), StringPool(DIEValueAllocator), PrevLabel(NULL), GlobalCUIndexCount(0) { Index: lib/MC/MCAsmInfo.cpp =================================================================== --- lib/MC/MCAsmInfo.cpp +++ lib/MC/MCAsmInfo.cpp @@ -81,7 +81,7 @@ HiddenDeclarationVisibilityAttr = MCSA_Hidden; ProtectedVisibilityAttr = MCSA_Protected; HasLEB128 = false; - SupportsDebugInformation = false; + DebugInformationType = DebugInformation::None; ExceptionsType = ExceptionHandling::None; DwarfUsesInlineInfoSection = false; DwarfSectionOffsetDirective = 0; Index: lib/MC/MCAsmInfoCOFF.cpp =================================================================== --- lib/MC/MCAsmInfoCOFF.cpp +++ lib/MC/MCAsmInfoCOFF.cpp @@ -35,7 +35,7 @@ // Set up DWARF directives HasLEB128 = true; // Target asm supports leb128 directives (little-endian) - SupportsDebugInformation = true; + DebugInformationType = DebugInformation::Dwarf; DwarfSectionOffsetDirective = "\t.secrel32\t"; HasMicrosoftFastStdCallMangling = true; } Index: lib/MC/MCObjectFileInfo.cpp =================================================================== --- lib/MC/MCObjectFileInfo.cpp +++ lib/MC/MCObjectFileInfo.cpp @@ -563,6 +563,18 @@ COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE, SectionKind::getDataRel()); + DebugSSection = + Ctx->getCOFFSection(".debug$S", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_DISCARDABLE, + SectionKind::getDataRel()); + DebugTSection = + Ctx->getCOFFSection(".debug$T", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_DISCARDABLE, + SectionKind::getDataRel()); } void MCObjectFileInfo::InitMCObjectFileInfo(StringRef TT, Reloc::Model relocm, Index: lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp +++ lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp @@ -31,7 +31,7 @@ Code32Directive = ".code\t32"; UseDataRegionDirectives = true; - SupportsDebugInformation = true; + DebugInformationType = DebugInformation::Dwarf; // Exceptions handling ExceptionsType = ExceptionHandling::SjLj; @@ -52,7 +52,7 @@ WeakRefDirective = "\t.weak\t"; HasLEB128 = true; - SupportsDebugInformation = true; + DebugInformationType = DebugInformation::Dwarf; // Exceptions handling if (EnableARMEHABI) Index: lib/Target/MBlaze/MCTargetDesc/MBlazeMCAsmInfo.cpp =================================================================== --- lib/Target/MBlaze/MCTargetDesc/MBlazeMCAsmInfo.cpp +++ lib/Target/MBlaze/MCTargetDesc/MBlazeMCAsmInfo.cpp @@ -19,7 +19,7 @@ MBlazeMCAsmInfo::MBlazeMCAsmInfo() { IsLittleEndian = false; StackGrowsUp = false; - SupportsDebugInformation = true; + DebugInformationType = DebugInformation::Dwarf; AlignmentIsInBytes = false; PrivateGlobalPrefix = "$"; GPRel32Directive = "\t.gpword\t"; Index: lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp +++ lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp @@ -35,7 +35,7 @@ GPRel64Directive = "\t.gpdword\t"; WeakRefDirective = "\t.weak\t"; - SupportsDebugInformation = true; + DebugInformationType = DebugInformation::Dwarf; ExceptionsType = ExceptionHandling::DwarfCFI; HasLEB128 = true; DwarfRegNumForCFI = true; Index: lib/Target/NVPTX/MCTargetDesc/NVPTXMCAsmInfo.cpp =================================================================== --- lib/Target/NVPTX/MCTargetDesc/NVPTXMCAsmInfo.cpp +++ lib/Target/NVPTX/MCTargetDesc/NVPTXMCAsmInfo.cpp @@ -46,7 +46,8 @@ InlineAsmStart = " inline asm"; InlineAsmEnd = " inline asm"; - SupportsDebugInformation = CompileForDebugging; + DebugInformationType = CompileForDebugging ? DebugInformation::Dwarf + : DebugInformation::None; HasDotTypeDotSizeDirective = false; Data8bitsDirective = " .b8 "; Index: lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp =================================================================== --- lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp +++ lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp @@ -29,7 +29,7 @@ Data64bitsDirective = 0; // We can't emit a 64-bit unit in PPC32 mode. AssemblerDialect = 1; // New-Style mnemonics. - SupportsDebugInformation= true; // Debug information. + DebugInformationType = DebugInformation::Dwarf; // Debug information. } void PPCLinuxMCAsmInfo::anchor() { } @@ -51,7 +51,7 @@ UsesELFSectionDirectiveForBSS = true; // Debug Information - SupportsDebugInformation = true; + DebugInformationType = DebugInformation::Dwarf; PCSymbol = "."; Index: lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp =================================================================== --- lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp +++ lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp @@ -30,8 +30,8 @@ ZeroDirective = "\t.skip\t"; CommentString = "!"; HasLEB128 = true; - SupportsDebugInformation = true; - + DebugInformationType = DebugInformation::Dwarf; + SunStyleELFSectionSwitchSyntax = true; UsesELFSectionDirectiveForBSS = true; Index: lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp =================================================================== --- lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp +++ lib/Target/X86/MCTargetDesc/X86MCAsmInfo.cpp @@ -61,7 +61,7 @@ CommentString = "##"; PCSymbol = "."; - SupportsDebugInformation = true; + DebugInformationType = DebugInformation::Dwarf; DwarfUsesInlineInfoSection = true; UseDataRegionDirectives = MarkedJTDataRegions; @@ -91,7 +91,7 @@ HasLEB128 = true; // Target asm supports leb128 directives (little-endian) // Debug Information - SupportsDebugInformation = true; + DebugInformationType = DebugInformation::Dwarf; // Exceptions handling ExceptionsType = ExceptionHandling::DwarfCFI; @@ -131,6 +131,8 @@ AssemblerDialect = AsmWriterFlavor; TextAlignFillValue = 0x90; + + DebugInformationType = DebugInformation::CodeView; } void X86MCAsmInfoGNUCOFF::anchor() { } Index: lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.cpp =================================================================== --- lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.cpp +++ lib/Target/XCore/MCTargetDesc/XCoreMCAsmInfo.cpp @@ -14,13 +14,13 @@ void XCoreMCAsmInfo::anchor() { } XCoreMCAsmInfo::XCoreMCAsmInfo(const Target &T, StringRef TT) { - SupportsDebugInformation = true; + DebugInformationType = DebugInformation::Dwarf; Data16bitsDirective = "\t.short\t"; Data32bitsDirective = "\t.long\t"; Data64bitsDirective = 0; ZeroDirective = "\t.space\t"; CommentString = "#"; - + PrivateGlobalPrefix = ".L"; AscizDirective = ".asciiz"; WeakDefDirective = "\t.weak\t";