| //===- dibuilder.go - Bindings for DIBuilder ------------------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines bindings for the DIBuilder class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| package llvm |
| |
| /* |
| #include "DIBuilderBindings.h" |
| #include <stdlib.h> |
| */ |
| 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 |
| FlagBlockByrefStruct |
| 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.LLVMNewDIBuilder(m.C) |
| return &DIBuilder{ref: d, m: m} |
| } |
| |
| // Destroy destroys the DIBuilder. |
| func (d *DIBuilder) Destroy() { |
| C.LLVMDIBuilderDestroy(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 |
| } |
| |
| // 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)) |
| result := C.LLVMDIBuilderCreateCompileUnit( |
| d.ref, |
| C.unsigned(cu.Language), |
| file, dir, |
| producer, |
| boolToCInt(cu.Optimized), |
| flags, |
| C.unsigned(cu.RuntimeVersion), |
| ) |
| return Metadata{C: result} |
| } |
| |
| // CreateCompileUnit 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, cdir) |
| return Metadata{C: result} |
| } |
| |
| // DILexicalBlock holds the values for creating lexical block debug metadata. |
| type DILexicalBlock struct { |
| File Metadata |
| Line int |
| Column int |
| } |
| |
| // CreateCompileUnit 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 |
| Function Value |
| } |
| |
| // CreateCompileUnit 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, |
| linkageName, |
| f.File.C, |
| C.unsigned(f.Line), |
| f.Type.C, |
| boolToCInt(f.LocalToUnit), |
| boolToCInt(f.IsDefinition), |
| C.unsigned(f.ScopeLine), |
| C.unsigned(f.Flags), |
| boolToCInt(f.Optimized), |
| f.Function.C, |
| ) |
| return Metadata{C: result} |
| } |
| |
| // DILocalVariable holds the values for creating local variable debug metadata. |
| type DILocalVariable struct { |
| Tag dwarf.Tag |
| 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 if it is an argument, or 0 otherwise. |
| ArgNo int |
| } |
| |
| // CreateLocalVariable creates local variable debug metadata. |
| func (d *DIBuilder) CreateLocalVariable(scope Metadata, v DILocalVariable) Metadata { |
| name := C.CString(v.Name) |
| defer C.free(unsafe.Pointer(name)) |
| result := C.LLVMDIBuilderCreateLocalVariable( |
| d.ref, |
| C.unsigned(v.Tag), |
| scope.C, |
| name, |
| v.File.C, |
| C.unsigned(v.Line), |
| v.Type.C, |
| boolToCInt(v.AlwaysPreserve), |
| C.unsigned(v.Flags), |
| C.unsigned(v.ArgNo), |
| ) |
| return Metadata{C: result} |
| } |
| |
| // DIBasicType holds the values for creating basic type debug metadata. |
| type DIBasicType struct { |
| Name string |
| SizeInBits uint64 |
| AlignInBits 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.uint64_t(t.SizeInBits), |
| C.uint64_t(t.AlignInBits), |
| C.unsigned(t.Encoding), |
| ) |
| return Metadata{C: result} |
| } |
| |
| // DIPointerType holds the values for creating pointer type debug metadata. |
| type DIPointerType struct { |
| Pointee Metadata |
| SizeInBits uint64 |
| AlignInBits uint64 // optional |
| Name string // optional |
| } |
| |
| // CreateBasicType creates basic type debug metadata. |
| 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.uint64_t(t.AlignInBits), |
| 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 |
| } |
| |
| // CreateSubroutineType creates subroutine type debug metadata. |
| func (d *DIBuilder) CreateSubroutineType(t DISubroutineType) Metadata { |
| params := d.getOrCreateTypeArray(t.Parameters) |
| result := C.LLVMDIBuilderCreateSubroutineType(d.ref, t.File.C, params.C) |
| 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 uint64 |
| Flags int |
| DerivedFrom Metadata |
| Elements []Metadata |
| } |
| |
| // CreateStructType creates struct type debug metadata. |
| func (d *DIBuilder) CreateStructType(scope Metadata, t DIStructType) Metadata { |
| elements := d.getOrCreateArray(t.Elements) |
| name := C.CString(t.Name) |
| defer C.free(unsafe.Pointer(name)) |
| result := C.LLVMDIBuilderCreateStructType( |
| d.ref, |
| scope.C, |
| name, |
| t.File.C, |
| C.unsigned(t.Line), |
| C.uint64_t(t.SizeInBits), |
| C.uint64_t(t.AlignInBits), |
| C.unsigned(t.Flags), |
| t.DerivedFrom.C, |
| elements.C, |
| ) |
| 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 uint64 |
| Flags int |
| } |
| |
| // CreateReplaceableCompositeType creates replaceable composite type debug metadata. |
| func (d *DIBuilder) CreateReplaceableCompositeType(scope Metadata, t DIReplaceableCompositeType) Metadata { |
| name := C.CString(t.Name) |
| defer C.free(unsafe.Pointer(name)) |
| result := C.LLVMDIBuilderCreateReplaceableCompositeType( |
| d.ref, |
| C.unsigned(t.Tag), |
| name, |
| scope.C, |
| t.File.C, |
| C.unsigned(t.Line), |
| C.unsigned(t.RuntimeLang), |
| C.uint64_t(t.SizeInBits), |
| C.uint64_t(t.AlignInBits), |
| C.unsigned(t.Flags), |
| ) |
| 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 uint64 |
| 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, |
| t.File.C, |
| C.unsigned(t.Line), |
| C.uint64_t(t.SizeInBits), |
| C.uint64_t(t.AlignInBits), |
| C.uint64_t(t.OffsetInBits), |
| C.unsigned(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 uint64 |
| 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 := d.getOrCreateArray(subscriptsSlice) |
| result := C.LLVMDIBuilderCreateArrayType( |
| d.ref, |
| C.uint64_t(t.SizeInBits), |
| C.uint64_t(t.AlignInBits), |
| t.ElementType.C, |
| subscripts.C, |
| ) |
| 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 |
| } |
| |
| // 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, |
| t.File.C, |
| C.unsigned(t.Line), |
| t.Context.C, |
| ) |
| 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, bb BasicBlock) Value { |
| result := C.LLVMDIBuilderInsertDeclareAtEnd(d.ref, v.C, diVarInfo.C, expr.C, 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, offset uint64, bb BasicBlock) Value { |
| result := C.LLVMDIBuilderInsertValueAtEnd(d.ref, v.C, C.uint64_t(offset), diVarInfo.C, expr.C, bb.C) |
| return Value{C: result} |
| } |
| |
| func boolToCInt(v bool) C.int { |
| if v { |
| return 1 |
| } |
| return 0 |
| } |