dibuilder.go   [plain text]


//===- 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}
}

// 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
}