//===- dibuilder.go - Bindings for DIBuilder ------------------------------===// // // 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 defines bindings for the DIBuilder class. // //===----------------------------------------------------------------------===// package llvm /* #include "IRBindings.h" #include */ import "C" import ( "debug/dwarf" "unsafe" ) type DwarfTag uint32 const ( DW_TAG_lexical_block DwarfTag = 0x0b DW_TAG_compile_unit DwarfTag = 0x11 DW_TAG_variable DwarfTag = 0x34 DW_TAG_base_type DwarfTag = 0x24 DW_TAG_pointer_type DwarfTag = 0x0F DW_TAG_structure_type DwarfTag = 0x13 DW_TAG_subroutine_type DwarfTag = 0x15 DW_TAG_file_type DwarfTag = 0x29 DW_TAG_subprogram DwarfTag = 0x2E DW_TAG_auto_variable DwarfTag = 0x100 DW_TAG_arg_variable DwarfTag = 0x101 ) const ( FlagPrivate = 1 << iota FlagProtected FlagFwdDecl FlagAppleBlock FlagReserved FlagVirtual FlagArtificial FlagExplicit FlagPrototyped FlagObjcClassComplete FlagObjectPointer FlagVector FlagStaticMember FlagIndirectVariable ) type DwarfLang uint32 const ( // http://dwarfstd.org/ShowIssue.php?issue=101014.1&type=open DW_LANG_Go DwarfLang = 0x0016 ) type DwarfTypeEncoding uint32 const ( DW_ATE_address DwarfTypeEncoding = 0x01 DW_ATE_boolean DwarfTypeEncoding = 0x02 DW_ATE_complex_float DwarfTypeEncoding = 0x03 DW_ATE_float DwarfTypeEncoding = 0x04 DW_ATE_signed DwarfTypeEncoding = 0x05 DW_ATE_signed_char DwarfTypeEncoding = 0x06 DW_ATE_unsigned DwarfTypeEncoding = 0x07 DW_ATE_unsigned_char DwarfTypeEncoding = 0x08 DW_ATE_imaginary_float DwarfTypeEncoding = 0x09 DW_ATE_packed_decimal DwarfTypeEncoding = 0x0a DW_ATE_numeric_string DwarfTypeEncoding = 0x0b DW_ATE_edited DwarfTypeEncoding = 0x0c DW_ATE_signed_fixed DwarfTypeEncoding = 0x0d DW_ATE_unsigned_fixed DwarfTypeEncoding = 0x0e DW_ATE_decimal_float DwarfTypeEncoding = 0x0f DW_ATE_UTF DwarfTypeEncoding = 0x10 DW_ATE_lo_user DwarfTypeEncoding = 0x80 DW_ATE_hi_user DwarfTypeEncoding = 0xff ) // DIBuilder is a wrapper for the LLVM DIBuilder class. type DIBuilder struct { ref C.LLVMDIBuilderRef m Module } // NewDIBuilder creates a new DIBuilder, associated with the given module. func NewDIBuilder(m Module) *DIBuilder { d := C.LLVMCreateDIBuilder(m.C) return &DIBuilder{ref: d, m: m} } // Destroy destroys the DIBuilder. func (d *DIBuilder) Destroy() { C.LLVMDisposeDIBuilder(d.ref) } // FInalize finalizes the debug information generated by the DIBuilder. func (d *DIBuilder) Finalize() { C.LLVMDIBuilderFinalize(d.ref) } // DICompileUnit holds the values for creating compile unit debug metadata. type DICompileUnit struct { Language DwarfLang File string Dir string Producer string Optimized bool Flags string RuntimeVersion int SysRoot string SDK string } // CreateCompileUnit creates compile unit debug metadata. func (d *DIBuilder) CreateCompileUnit(cu DICompileUnit) Metadata { file := C.CString(cu.File) defer C.free(unsafe.Pointer(file)) dir := C.CString(cu.Dir) defer C.free(unsafe.Pointer(dir)) producer := C.CString(cu.Producer) defer C.free(unsafe.Pointer(producer)) flags := C.CString(cu.Flags) defer C.free(unsafe.Pointer(flags)) sysroot := C.CString(cu.SysRoot) defer C.free(unsafe.Pointer(sysroot)) sdk := C.CString(cu.SDK) defer C.free(unsafe.Pointer(sdk)) result := C.LLVMDIBuilderCreateCompileUnit( d.ref, C.LLVMDWARFSourceLanguage(cu.Language), C.LLVMDIBuilderCreateFile(d.ref, file, C.size_t(len(cu.File)), dir, C.size_t(len(cu.Dir))), producer, C.size_t(len(cu.Producer)), C.LLVMBool(boolToCInt(cu.Optimized)), flags, C.size_t(len(cu.Flags)), C.unsigned(cu.RuntimeVersion), /*SplitName=*/ nil, 0, C.LLVMDWARFEmissionFull, /*DWOId=*/ 0, /*SplitDebugInlining*/ C.LLVMBool(boolToCInt(true)), /*DebugInfoForProfiling*/ C.LLVMBool(boolToCInt(false)), sysroot, C.size_t(len(cu.SysRoot)), sdk, C.size_t(len(cu.SDK)), ) return Metadata{C: result} } // CreateFile creates file debug metadata. func (d *DIBuilder) CreateFile(filename, dir string) Metadata { cfilename := C.CString(filename) defer C.free(unsafe.Pointer(cfilename)) cdir := C.CString(dir) defer C.free(unsafe.Pointer(cdir)) result := C.LLVMDIBuilderCreateFile(d.ref, cfilename, C.size_t(len(filename)), cdir, C.size_t(len(dir))) return Metadata{C: result} } // DILexicalBlock holds the values for creating lexical block debug metadata. type DILexicalBlock struct { File Metadata Line int Column int } // CreateLexicalBlock creates lexical block debug metadata. func (d *DIBuilder) CreateLexicalBlock(diScope Metadata, b DILexicalBlock) Metadata { result := C.LLVMDIBuilderCreateLexicalBlock( d.ref, diScope.C, b.File.C, C.unsigned(b.Line), C.unsigned(b.Column), ) return Metadata{C: result} } func (d *DIBuilder) CreateLexicalBlockFile(diScope Metadata, diFile Metadata, discriminator int) Metadata { result := C.LLVMDIBuilderCreateLexicalBlockFile(d.ref, diScope.C, diFile.C, C.unsigned(discriminator)) return Metadata{C: result} } // DIFunction holds the values for creating function debug metadata. type DIFunction struct { Name string LinkageName string File Metadata Line int Type Metadata LocalToUnit bool IsDefinition bool ScopeLine int Flags int Optimized bool } // CreateFunction creates function debug metadata. func (d *DIBuilder) CreateFunction(diScope Metadata, f DIFunction) Metadata { name := C.CString(f.Name) defer C.free(unsafe.Pointer(name)) linkageName := C.CString(f.LinkageName) defer C.free(unsafe.Pointer(linkageName)) result := C.LLVMDIBuilderCreateFunction( d.ref, diScope.C, name, C.size_t(len(f.Name)), linkageName, C.size_t(len(f.LinkageName)), f.File.C, C.unsigned(f.Line), f.Type.C, C.LLVMBool(boolToCInt(f.LocalToUnit)), C.LLVMBool(boolToCInt(f.IsDefinition)), C.unsigned(f.ScopeLine), C.LLVMDIFlags(f.Flags), C.LLVMBool(boolToCInt(f.Optimized)), ) return Metadata{C: result} } // DIAutoVariable holds the values for creating auto variable debug metadata. type DIAutoVariable struct { Name string File Metadata Line int Type Metadata AlwaysPreserve bool Flags int AlignInBits uint32 } // CreateAutoVariable creates local variable debug metadata. func (d *DIBuilder) CreateAutoVariable(scope Metadata, v DIAutoVariable) Metadata { name := C.CString(v.Name) defer C.free(unsafe.Pointer(name)) result := C.LLVMDIBuilderCreateAutoVariable( d.ref, scope.C, name, C.size_t(len(v.Name)), v.File.C, C.unsigned(v.Line), v.Type.C, C.LLVMBool(boolToCInt(v.AlwaysPreserve)), C.LLVMDIFlags(v.Flags), C.uint32_t(v.AlignInBits), ) return Metadata{C: result} } // DIParameterVariable holds the values for creating parameter variable debug metadata. type DIParameterVariable struct { Name string File Metadata Line int Type Metadata AlwaysPreserve bool Flags int // ArgNo is the 1-based index of the argument in the function's // parameter list. ArgNo int } // CreateParameterVariable creates parameter variable debug metadata. func (d *DIBuilder) CreateParameterVariable(scope Metadata, v DIParameterVariable) Metadata { name := C.CString(v.Name) defer C.free(unsafe.Pointer(name)) result := C.LLVMDIBuilderCreateParameterVariable( d.ref, scope.C, name, C.size_t(len(v.Name)), C.unsigned(v.ArgNo), v.File.C, C.unsigned(v.Line), v.Type.C, C.LLVMBool(boolToCInt(v.AlwaysPreserve)), C.LLVMDIFlags(v.Flags), ) return Metadata{C: result} } // DIBasicType holds the values for creating basic type debug metadata. type DIBasicType struct { Name string SizeInBits uint64 Encoding DwarfTypeEncoding } // CreateBasicType creates basic type debug metadata. func (d *DIBuilder) CreateBasicType(t DIBasicType) Metadata { name := C.CString(t.Name) defer C.free(unsafe.Pointer(name)) result := C.LLVMDIBuilderCreateBasicType( d.ref, name, C.size_t(len(t.Name)), C.uint64_t(t.SizeInBits), C.LLVMDWARFTypeEncoding(t.Encoding), C.LLVMDIFlags(0), ) return Metadata{C: result} } // DIPointerType holds the values for creating pointer type debug metadata. type DIPointerType struct { Pointee Metadata SizeInBits uint64 AlignInBits uint32 // optional AddressSpace uint32 Name string // optional } // CreatePointerType creates a type that represents a pointer to another type. func (d *DIBuilder) CreatePointerType(t DIPointerType) Metadata { name := C.CString(t.Name) defer C.free(unsafe.Pointer(name)) result := C.LLVMDIBuilderCreatePointerType( d.ref, t.Pointee.C, C.uint64_t(t.SizeInBits), C.uint32_t(t.AlignInBits), C.unsigned(t.AddressSpace), name, C.size_t(len(t.Name)), ) return Metadata{C: result} } // DISubroutineType holds the values for creating subroutine type debug metadata. type DISubroutineType struct { // File is the file in which the subroutine type is defined. File Metadata // Parameters contains the subroutine parameter types, // including the return type at the 0th index. Parameters []Metadata Flags int } // CreateSubroutineType creates subroutine type debug metadata. func (d *DIBuilder) CreateSubroutineType(t DISubroutineType) Metadata { params, length := llvmMetadataRefs(t.Parameters) result := C.LLVMDIBuilderCreateSubroutineType( d.ref, t.File.C, params, length, C.LLVMDIFlags(t.Flags), ) return Metadata{C: result} } // DIStructType holds the values for creating struct type debug metadata. type DIStructType struct { Name string File Metadata Line int SizeInBits uint64 AlignInBits uint32 Flags int DerivedFrom Metadata Elements []Metadata VTableHolder Metadata // optional UniqueID string } // CreateStructType creates struct type debug metadata. func (d *DIBuilder) CreateStructType(scope Metadata, t DIStructType) Metadata { elements, length := llvmMetadataRefs(t.Elements) name := C.CString(t.Name) uniqueID := C.CString(t.UniqueID) defer C.free(unsafe.Pointer(name)) defer C.free(unsafe.Pointer(uniqueID)) result := C.LLVMDIBuilderCreateStructType( d.ref, scope.C, name, C.size_t(len(t.Name)), t.File.C, C.unsigned(t.Line), C.uint64_t(t.SizeInBits), C.uint32_t(t.AlignInBits), C.LLVMDIFlags(t.Flags), t.DerivedFrom.C, elements, length, C.unsigned(0), // Optional Objective-C runtime version. t.VTableHolder.C, uniqueID, C.size_t(len(t.UniqueID)), ) return Metadata{C: result} } // DIReplaceableCompositeType holds the values for creating replaceable // composite type debug metadata. type DIReplaceableCompositeType struct { Tag dwarf.Tag Name string File Metadata Line int RuntimeLang int SizeInBits uint64 AlignInBits uint32 Flags int UniqueID string } // CreateReplaceableCompositeType creates replaceable composite type debug metadata. func (d *DIBuilder) CreateReplaceableCompositeType(scope Metadata, t DIReplaceableCompositeType) Metadata { name := C.CString(t.Name) uniqueID := C.CString(t.UniqueID) defer C.free(unsafe.Pointer(name)) defer C.free(unsafe.Pointer(uniqueID)) result := C.LLVMDIBuilderCreateReplaceableCompositeType( d.ref, C.unsigned(t.Tag), name, C.size_t(len(t.Name)), scope.C, t.File.C, C.unsigned(t.Line), C.unsigned(t.RuntimeLang), C.uint64_t(t.SizeInBits), C.uint32_t(t.AlignInBits), C.LLVMDIFlags(t.Flags), uniqueID, C.size_t(len(t.UniqueID)), ) return Metadata{C: result} } // DIMemberType holds the values for creating member type debug metadata. type DIMemberType struct { Name string File Metadata Line int SizeInBits uint64 AlignInBits uint32 OffsetInBits uint64 Flags int Type Metadata } // CreateMemberType creates struct type debug metadata. func (d *DIBuilder) CreateMemberType(scope Metadata, t DIMemberType) Metadata { name := C.CString(t.Name) defer C.free(unsafe.Pointer(name)) result := C.LLVMDIBuilderCreateMemberType( d.ref, scope.C, name, C.size_t(len(t.Name)), t.File.C, C.unsigned(t.Line), C.uint64_t(t.SizeInBits), C.uint32_t(t.AlignInBits), C.uint64_t(t.OffsetInBits), C.LLVMDIFlags(t.Flags), t.Type.C, ) return Metadata{C: result} } // DISubrange describes an integer value range. type DISubrange struct { Lo int64 Count int64 } // DIArrayType holds the values for creating array type debug metadata. type DIArrayType struct { SizeInBits uint64 AlignInBits uint32 ElementType Metadata Subscripts []DISubrange } // CreateArrayType creates struct type debug metadata. func (d *DIBuilder) CreateArrayType(t DIArrayType) Metadata { subscriptsSlice := make([]Metadata, len(t.Subscripts)) for i, s := range t.Subscripts { subscriptsSlice[i] = d.getOrCreateSubrange(s.Lo, s.Count) } subscripts, length := llvmMetadataRefs(subscriptsSlice) result := C.LLVMDIBuilderCreateArrayType( d.ref, C.uint64_t(t.SizeInBits), C.uint32_t(t.AlignInBits), t.ElementType.C, subscripts, length, ) return Metadata{C: result} } // DITypedef holds the values for creating typedef type debug metadata. type DITypedef struct { Type Metadata Name string File Metadata Line int Context Metadata AlignInBits uint32 } // CreateTypedef creates typedef type debug metadata. func (d *DIBuilder) CreateTypedef(t DITypedef) Metadata { name := C.CString(t.Name) defer C.free(unsafe.Pointer(name)) result := C.LLVMDIBuilderCreateTypedef( d.ref, t.Type.C, name, C.size_t(len(t.Name)), t.File.C, C.unsigned(t.Line), t.Context.C, C.uint32_t(t.AlignInBits), ) return Metadata{C: result} } // getOrCreateSubrange gets a metadata node for the specified subrange, // creating if required. func (d *DIBuilder) getOrCreateSubrange(lo, count int64) Metadata { result := C.LLVMDIBuilderGetOrCreateSubrange(d.ref, C.int64_t(lo), C.int64_t(count)) return Metadata{C: result} } // getOrCreateArray gets a metadata node containing the specified values, // creating if required. func (d *DIBuilder) getOrCreateArray(values []Metadata) Metadata { if len(values) == 0 { return Metadata{} } data, length := llvmMetadataRefs(values) result := C.LLVMDIBuilderGetOrCreateArray(d.ref, data, C.size_t(length)) return Metadata{C: result} } // getOrCreateTypeArray gets a metadata node for a type array containing the // specified values, creating if required. func (d *DIBuilder) getOrCreateTypeArray(values []Metadata) Metadata { if len(values) == 0 { return Metadata{} } data, length := llvmMetadataRefs(values) result := C.LLVMDIBuilderGetOrCreateTypeArray(d.ref, data, C.size_t(length)) return Metadata{C: result} } // CreateExpression creates a new descriptor for the specified // variable which has a complex address expression for its address. func (d *DIBuilder) CreateExpression(addr []int64) Metadata { var data *C.int64_t if len(addr) > 0 { data = (*C.int64_t)(unsafe.Pointer(&addr[0])) } result := C.LLVMDIBuilderCreateExpression(d.ref, data, C.size_t(len(addr))) return Metadata{C: result} } // InsertDeclareAtEnd inserts a call to llvm.dbg.declare at the end of the // specified basic block for the given value and associated debug metadata. func (d *DIBuilder) InsertDeclareAtEnd(v Value, diVarInfo, expr Metadata, l DebugLoc, bb BasicBlock) Value { loc := C.LLVMDIBuilderCreateDebugLocation( d.m.Context().C, C.uint(l.Line), C.uint(l.Col), l.Scope.C, l.InlinedAt.C) result := C.LLVMDIBuilderInsertDeclareAtEnd(d.ref, v.C, diVarInfo.C, expr.C, loc, bb.C) return Value{C: result} } // InsertValueAtEnd inserts a call to llvm.dbg.value at the end of the // specified basic block for the given value and associated debug metadata. func (d *DIBuilder) InsertValueAtEnd(v Value, diVarInfo, expr Metadata, l DebugLoc, bb BasicBlock) Value { loc := C.LLVMDIBuilderCreateDebugLocation( d.m.Context().C, C.uint(l.Line), C.uint(l.Col), l.Scope.C, l.InlinedAt.C) result := C.LLVMDIBuilderInsertDbgValueAtEnd(d.ref, v.C, diVarInfo.C, expr.C, loc, bb.C) return Value{C: result} } func (v Value) SetSubprogram(sp Metadata) { C.LLVMSetSubprogram(v.C, sp.C) } func (v Value) Subprogram() (md Metadata) { md.C = C.LLVMGetSubprogram(v.C) return } func boolToCInt(v bool) C.int { if v { return 1 } return 0 } //------------------------------------------------------------------------- // llvm.Metadata //------------------------------------------------------------------------- func (c Context) TemporaryMDNode(mds []Metadata) (md Metadata) { ptr, nvals := llvmMetadataRefs(mds) md.C = C.LLVMTemporaryMDNode(c.C, ptr, C.size_t(nvals)) return } func (md Metadata) ReplaceAllUsesWith(new Metadata) { C.LLVMMetadataReplaceAllUsesWith(md.C, new.C) } type MetadataKind C.LLVMMetadataKind const ( MDStringMetadataKind = C.LLVMMDStringMetadataKind ConstantAsMetadataMetadataKind = C.LLVMConstantAsMetadataMetadataKind LocalAsMetadataMetadataKind = C.LLVMLocalAsMetadataMetadataKind DistinctMDOperandPlaceholderMetadataKind = C.LLVMDistinctMDOperandPlaceholderMetadataKind MDTupleMetadataKind = C.LLVMMDTupleMetadataKind DILocationMetadataKind = C.LLVMDILocationMetadataKind DIExpressionMetadataKind = C.LLVMDIExpressionMetadataKind DIGlobalVariableExpressionMetadataKind = C.LLVMDIGlobalVariableExpressionMetadataKind GenericDINodeMetadataKind = C.LLVMGenericDINodeMetadataKind DISubrangeMetadataKind = C.LLVMDISubrangeMetadataKind DIEnumeratorMetadataKind = C.LLVMDIEnumeratorMetadataKind DIBasicTypeMetadataKind = C.LLVMDIBasicTypeMetadataKind DIDerivedTypeMetadataKind = C.LLVMDIDerivedTypeMetadataKind DICompositeTypeMetadataKind = C.LLVMDICompositeTypeMetadataKind DISubroutineTypeMetadataKind = C.LLVMDISubroutineTypeMetadataKind DIFileMetadataKind = C.LLVMDIFileMetadataKind DICompileUnitMetadataKind = C.LLVMDICompileUnitMetadataKind DISubprogramMetadataKind = C.LLVMDISubprogramMetadataKind DILexicalBlockMetadataKind = C.LLVMDILexicalBlockMetadataKind DILexicalBlockFileMetadataKind = C.LLVMDILexicalBlockFileMetadataKind DINamespaceMetadataKind = C.LLVMDINamespaceMetadataKind DIModuleMetadataKind = C.LLVMDIModuleMetadataKind DITemplateTypeParameterMetadataKind = C.LLVMDITemplateTypeParameterMetadataKind DITemplateValueParameterMetadataKind = C.LLVMDITemplateValueParameterMetadataKind DIGlobalVariableMetadataKind = C.LLVMDIGlobalVariableMetadataKind DILocalVariableMetadataKind = C.LLVMDILocalVariableMetadataKind DILabelMetadataKind = C.LLVMDILabelMetadataKind DIObjCPropertyMetadataKind = C.LLVMDIObjCPropertyMetadataKind DIImportedEntityMetadataKind = C.LLVMDIImportedEntityMetadataKind DIMacroMetadataKind = C.LLVMDIMacroMetadataKind DIMacroFileMetadataKind = C.LLVMDIMacroFileMetadataKind DICommonBlockMetadataKind = C.LLVMDICommonBlockMetadataKind ) // Kind returns the metadata kind. func (md Metadata) Kind() MetadataKind { return MetadataKind(C.LLVMGetMetadataKind(md.C)) } // FileDirectory returns the directory of a DIFile metadata node. func (md Metadata) FileDirectory() string { var length C.unsigned ptr := C.LLVMDIFileGetDirectory(md.C, &length) return string(((*[1 << 20]byte)(unsafe.Pointer(ptr)))[:length:length]) } // FileFilename returns the filename of a DIFile metadata node. func (md Metadata) FileFilename() string { var length C.unsigned ptr := C.LLVMDIFileGetFilename(md.C, &length) return string(((*[1 << 20]byte)(unsafe.Pointer(ptr)))[:length:length]) } // FileSource returns the source of a DIFile metadata node. func (md Metadata) FileSource() string { var length C.unsigned ptr := C.LLVMDIFileGetSource(md.C, &length) return string(((*[1 << 20]byte)(unsafe.Pointer(ptr)))[:length:length]) } // LocationLine returns the line number of a DILocation. func (md Metadata) LocationLine() uint { return uint(C.LLVMDILocationGetLine(md.C)) } // LocationColumn returns the column (offset from the start of the line) of a // DILocation. func (md Metadata) LocationColumn() uint { return uint(C.LLVMDILocationGetColumn(md.C)) } // LocationScope returns the local scope associated with this debug location. func (md Metadata) LocationScope() Metadata { return Metadata{C.LLVMDILocationGetScope(md.C)} } // LocationInlinedAt return the "inline at" location associated with this debug // location. func (md Metadata) LocationInlinedAt() Metadata { return Metadata{C.LLVMDILocationGetInlinedAt(md.C)} } // ScopeFile returns the file (DIFile) of a given scope. func (md Metadata) ScopeFile() Metadata { return Metadata{C.LLVMDIScopeGetFile(md.C)} }