github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/debug/debug.go (about)

     1  //===- debug.go - debug info builder --------------------------------------===//
     2  //
     3  //                     The LLVM Compiler Infrastructure
     4  //
     5  // This file is distributed under the University of Illinois Open Source
     6  // License. See LICENSE.TXT for details.
     7  //
     8  //===----------------------------------------------------------------------===//
     9  //
    10  // This package builds LLVM debug info from go/* data structures.
    11  //
    12  //===----------------------------------------------------------------------===//
    13  
    14  package debug
    15  
    16  import (
    17  	"debug/dwarf"
    18  	"fmt"
    19  	"go/token"
    20  	"os"
    21  	"strings"
    22  
    23  	"llvm.org/llgo/third_party/gotools/go/ssa"
    24  	"llvm.org/llgo/third_party/gotools/go/types"
    25  	"llvm.org/llgo/third_party/gotools/go/types/typeutil"
    26  
    27  	"llvm.org/llvm/bindings/go/llvm"
    28  )
    29  
    30  const (
    31  	// non-standard debug metadata tags
    32  	tagAutoVariable dwarf.Tag = 0x100
    33  	tagArgVariable  dwarf.Tag = 0x101
    34  )
    35  
    36  type PrefixMap struct {
    37  	Source, Replacement string
    38  }
    39  
    40  // DIBuilder builds debug metadata for Go programs.
    41  type DIBuilder struct {
    42  	// builder is the current builder; there is one per CU.
    43  	builder    *llvm.DIBuilder
    44  	module     llvm.Module
    45  	files      map[*token.File]llvm.Metadata
    46  	cu, fn, lb llvm.Metadata
    47  	fnFile     string
    48  	sizes      types.Sizes
    49  	fset       *token.FileSet
    50  	prefixMaps []PrefixMap
    51  	types      typeutil.Map
    52  	voidType   llvm.Metadata
    53  }
    54  
    55  // NewDIBuilder creates a new debug information builder.
    56  func NewDIBuilder(sizes types.Sizes, module llvm.Module, fset *token.FileSet, prefixMaps []PrefixMap) *DIBuilder {
    57  	var d DIBuilder
    58  	d.module = module
    59  	d.files = make(map[*token.File]llvm.Metadata)
    60  	d.sizes = sizes
    61  	d.fset = fset
    62  	d.prefixMaps = prefixMaps
    63  	d.builder = llvm.NewDIBuilder(d.module)
    64  	d.cu = d.createCompileUnit()
    65  	return &d
    66  }
    67  
    68  // Destroy destroys the DIBuilder.
    69  func (d *DIBuilder) Destroy() {
    70  	d.builder.Destroy()
    71  }
    72  
    73  func (d *DIBuilder) scope() llvm.Metadata {
    74  	if d.lb.C != nil {
    75  		return d.lb
    76  	}
    77  	if d.fn.C != nil {
    78  		return d.fn
    79  	}
    80  	return d.cu
    81  }
    82  
    83  func (d *DIBuilder) remapFilePath(path string) string {
    84  	for _, pm := range d.prefixMaps {
    85  		if strings.HasPrefix(path, pm.Source) {
    86  			return pm.Replacement + path[len(pm.Source):]
    87  		}
    88  	}
    89  	return path
    90  }
    91  
    92  func (d *DIBuilder) getFile(file *token.File) llvm.Metadata {
    93  	if diFile := d.files[file]; diFile.C != nil {
    94  		return diFile
    95  	}
    96  	diFile := d.builder.CreateFile(d.remapFilePath(file.Name()), "")
    97  	d.files[file] = diFile
    98  	return diFile
    99  }
   100  
   101  // createCompileUnit creates and returns debug metadata for the compile
   102  // unit as a whole, using the first file in the file set as a representative
   103  // (the choice of file is arbitrary).
   104  func (d *DIBuilder) createCompileUnit() llvm.Metadata {
   105  	var file *token.File
   106  	d.fset.Iterate(func(f *token.File) bool {
   107  		file = f
   108  		return false
   109  	})
   110  	dir, err := os.Getwd()
   111  	if err != nil {
   112  		panic("could not get current directory: " + err.Error())
   113  	}
   114  	return d.builder.CreateCompileUnit(llvm.DICompileUnit{
   115  		Language: llvm.DW_LANG_Go,
   116  		File:     d.remapFilePath(file.Name()),
   117  		Dir:      dir,
   118  		Producer: "llgo",
   119  	})
   120  }
   121  
   122  // PushFunction creates debug metadata for the specified function,
   123  // and pushes it onto the scope stack.
   124  func (d *DIBuilder) PushFunction(fnptr llvm.Value, sig *types.Signature, pos token.Pos) {
   125  	var diFile llvm.Metadata
   126  	var line int
   127  	if file := d.fset.File(pos); file != nil {
   128  		d.fnFile = file.Name()
   129  		diFile = d.getFile(file)
   130  		line = file.Line(pos)
   131  	}
   132  	d.fn = d.builder.CreateFunction(d.scope(), llvm.DIFunction{
   133  		Name:         fnptr.Name(), // TODO(axw) unmangled name?
   134  		LinkageName:  fnptr.Name(),
   135  		File:         diFile,
   136  		Line:         line,
   137  		Type:         d.DIType(sig),
   138  		IsDefinition: true,
   139  		Function:     fnptr,
   140  	})
   141  }
   142  
   143  // PopFunction pops the previously pushed function off the scope stack.
   144  func (d *DIBuilder) PopFunction() {
   145  	d.lb = llvm.Metadata{}
   146  	d.fn = llvm.Metadata{}
   147  	d.fnFile = ""
   148  }
   149  
   150  // Declare creates an llvm.dbg.declare call for the specified function
   151  // parameter or local variable.
   152  func (d *DIBuilder) Declare(b llvm.Builder, v ssa.Value, llv llvm.Value, paramIndex int) {
   153  	tag := tagAutoVariable
   154  	if paramIndex >= 0 {
   155  		tag = tagArgVariable
   156  	}
   157  	var diFile llvm.Metadata
   158  	var line int
   159  	if file := d.fset.File(v.Pos()); file != nil {
   160  		line = file.Line(v.Pos())
   161  		diFile = d.getFile(file)
   162  	}
   163  	localVar := d.builder.CreateLocalVariable(d.scope(), llvm.DILocalVariable{
   164  		Tag:   tag,
   165  		Name:  llv.Name(),
   166  		File:  diFile,
   167  		Line:  line,
   168  		ArgNo: paramIndex + 1,
   169  		Type:  d.DIType(v.Type()),
   170  	})
   171  	expr := d.builder.CreateExpression(nil)
   172  	d.builder.InsertDeclareAtEnd(llv, localVar, expr, b.GetInsertBlock())
   173  }
   174  
   175  // Value creates an llvm.dbg.value call for the specified register value.
   176  func (d *DIBuilder) Value(b llvm.Builder, v ssa.Value, llv llvm.Value, paramIndex int) {
   177  	// TODO(axw)
   178  }
   179  
   180  // SetLocation sets the current debug location.
   181  func (d *DIBuilder) SetLocation(b llvm.Builder, pos token.Pos) {
   182  	if !pos.IsValid() {
   183  		return
   184  	}
   185  	position := d.fset.Position(pos)
   186  	d.lb = llvm.Metadata{}
   187  	if position.Filename != d.fnFile && position.Filename != "" {
   188  		// This can happen rarely, e.g. in init functions.
   189  		diFile := d.builder.CreateFile(d.remapFilePath(position.Filename), "")
   190  		d.lb = d.builder.CreateLexicalBlockFile(d.scope(), diFile, 0)
   191  	}
   192  	b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), d.scope(), llvm.Metadata{})
   193  }
   194  
   195  // Finalize must be called after all compilation units are translated,
   196  // generating the final debug metadata for the module.
   197  func (d *DIBuilder) Finalize() {
   198  	d.module.AddNamedMetadataOperand(
   199  		"llvm.module.flags",
   200  		llvm.GlobalContext().MDNode([]llvm.Metadata{
   201  			llvm.ConstInt(llvm.Int32Type(), 2, false).ConstantAsMetadata(), // Warn on mismatch
   202  			llvm.GlobalContext().MDString("Dwarf Version"),
   203  			llvm.ConstInt(llvm.Int32Type(), 4, false).ConstantAsMetadata(),
   204  		}),
   205  	)
   206  	d.module.AddNamedMetadataOperand(
   207  		"llvm.module.flags",
   208  		llvm.GlobalContext().MDNode([]llvm.Metadata{
   209  			llvm.ConstInt(llvm.Int32Type(), 1, false).ConstantAsMetadata(), // Error on mismatch
   210  			llvm.GlobalContext().MDString("Debug Info Version"),
   211  			llvm.ConstInt(llvm.Int32Type(), 2, false).ConstantAsMetadata(),
   212  		}),
   213  	)
   214  	d.builder.Finalize()
   215  }
   216  
   217  // DIType maps a Go type to DIType debug metadata value.
   218  func (d *DIBuilder) DIType(t types.Type) llvm.Metadata {
   219  	return d.typeDebugDescriptor(t, types.TypeString(nil, t))
   220  }
   221  
   222  func (d *DIBuilder) typeDebugDescriptor(t types.Type, name string) llvm.Metadata {
   223  	// Signature needs to be handled specially, to preprocess
   224  	// methods, moving the receiver to the parameter list.
   225  	if t, ok := t.(*types.Signature); ok {
   226  		return d.descriptorSignature(t, name)
   227  	}
   228  	if t == nil {
   229  		if d.voidType.C == nil {
   230  			d.voidType = d.builder.CreateBasicType(llvm.DIBasicType{Name: "void"})
   231  		}
   232  		return d.voidType
   233  	}
   234  	if dt, ok := d.types.At(t).(llvm.Metadata); ok {
   235  		return dt
   236  	}
   237  	dt := d.descriptor(t, name)
   238  	d.types.Set(t, dt)
   239  	return dt
   240  }
   241  
   242  func (d *DIBuilder) descriptor(t types.Type, name string) llvm.Metadata {
   243  	switch t := t.(type) {
   244  	case *types.Basic:
   245  		return d.descriptorBasic(t, name)
   246  	case *types.Pointer:
   247  		return d.descriptorPointer(t)
   248  	case *types.Struct:
   249  		return d.descriptorStruct(t, name)
   250  	case *types.Named:
   251  		return d.descriptorNamed(t)
   252  	case *types.Array:
   253  		return d.descriptorArray(t, name)
   254  	case *types.Slice:
   255  		return d.descriptorSlice(t, name)
   256  	case *types.Map:
   257  		return d.descriptorMap(t, name)
   258  	case *types.Chan:
   259  		return d.descriptorChan(t, name)
   260  	case *types.Interface:
   261  		return d.descriptorInterface(t, name)
   262  	default:
   263  		panic(fmt.Sprintf("unhandled type: %T", t))
   264  	}
   265  }
   266  
   267  func (d *DIBuilder) descriptorBasic(t *types.Basic, name string) llvm.Metadata {
   268  	switch t.Kind() {
   269  	case types.String:
   270  		return d.typeDebugDescriptor(types.NewStruct([]*types.Var{
   271  			types.NewVar(0, nil, "ptr", types.NewPointer(types.Typ[types.Uint8])),
   272  			types.NewVar(0, nil, "len", types.Typ[types.Int]),
   273  		}, nil), name)
   274  	case types.UnsafePointer:
   275  		return d.builder.CreateBasicType(llvm.DIBasicType{
   276  			Name:        name,
   277  			SizeInBits:  uint64(d.sizes.Sizeof(t) * 8),
   278  			AlignInBits: uint64(d.sizes.Alignof(t) * 8),
   279  			Encoding:    llvm.DW_ATE_unsigned,
   280  		})
   281  	default:
   282  		bt := llvm.DIBasicType{
   283  			Name:        t.String(),
   284  			SizeInBits:  uint64(d.sizes.Sizeof(t) * 8),
   285  			AlignInBits: uint64(d.sizes.Alignof(t) * 8),
   286  		}
   287  		switch bi := t.Info(); {
   288  		case bi&types.IsBoolean != 0:
   289  			bt.Encoding = llvm.DW_ATE_boolean
   290  		case bi&types.IsUnsigned != 0:
   291  			bt.Encoding = llvm.DW_ATE_unsigned
   292  		case bi&types.IsInteger != 0:
   293  			bt.Encoding = llvm.DW_ATE_signed
   294  		case bi&types.IsFloat != 0:
   295  			bt.Encoding = llvm.DW_ATE_float
   296  		case bi&types.IsComplex != 0:
   297  			bt.Encoding = llvm.DW_ATE_imaginary_float
   298  		case bi&types.IsUnsigned != 0:
   299  			bt.Encoding = llvm.DW_ATE_unsigned
   300  		default:
   301  			panic(fmt.Sprintf("unhandled: %#v", t))
   302  		}
   303  		return d.builder.CreateBasicType(bt)
   304  	}
   305  }
   306  
   307  func (d *DIBuilder) descriptorPointer(t *types.Pointer) llvm.Metadata {
   308  	return d.builder.CreatePointerType(llvm.DIPointerType{
   309  		Pointee:     d.DIType(t.Elem()),
   310  		SizeInBits:  uint64(d.sizes.Sizeof(t) * 8),
   311  		AlignInBits: uint64(d.sizes.Alignof(t) * 8),
   312  	})
   313  }
   314  
   315  func (d *DIBuilder) descriptorStruct(t *types.Struct, name string) llvm.Metadata {
   316  	fields := make([]*types.Var, t.NumFields())
   317  	for i := range fields {
   318  		fields[i] = t.Field(i)
   319  	}
   320  	offsets := d.sizes.Offsetsof(fields)
   321  	members := make([]llvm.Metadata, len(fields))
   322  	for i, f := range fields {
   323  		// TODO(axw) file/line where member is defined.
   324  		t := f.Type()
   325  		members[i] = d.builder.CreateMemberType(d.cu, llvm.DIMemberType{
   326  			Name:         f.Name(),
   327  			Type:         d.DIType(t),
   328  			SizeInBits:   uint64(d.sizes.Sizeof(t) * 8),
   329  			AlignInBits:  uint64(d.sizes.Alignof(t) * 8),
   330  			OffsetInBits: uint64(offsets[i] * 8),
   331  		})
   332  	}
   333  	// TODO(axw) file/line where struct is defined.
   334  	return d.builder.CreateStructType(d.cu, llvm.DIStructType{
   335  		Name:        name,
   336  		SizeInBits:  uint64(d.sizes.Sizeof(t) * 8),
   337  		AlignInBits: uint64(d.sizes.Alignof(t) * 8),
   338  		Elements:    members,
   339  	})
   340  }
   341  
   342  func (d *DIBuilder) descriptorNamed(t *types.Named) llvm.Metadata {
   343  	var diFile llvm.Metadata
   344  	var line int
   345  	if file := d.fset.File(t.Obj().Pos()); file != nil {
   346  		line = file.Line(t.Obj().Pos())
   347  		diFile = d.getFile(file)
   348  	}
   349  
   350  	// Create a placeholder for the named type, to terminate cycles.
   351  	name := t.Obj().Name()
   352  	placeholder := d.builder.CreateReplaceableCompositeType(d.scope(), llvm.DIReplaceableCompositeType{
   353  		Tag:  dwarf.TagStructType,
   354  		Name: name,
   355  		File: diFile,
   356  		Line: line,
   357  	})
   358  	d.types.Set(t, placeholder)
   359  
   360  	typedef := d.builder.CreateTypedef(llvm.DITypedef{
   361  		Type: d.DIType(t.Underlying()),
   362  		Name: name,
   363  		File: diFile,
   364  		Line: line,
   365  	})
   366  	placeholder.ReplaceAllUsesWith(typedef)
   367  	return typedef
   368  }
   369  
   370  func (d *DIBuilder) descriptorArray(t *types.Array, name string) llvm.Metadata {
   371  	return d.builder.CreateArrayType(llvm.DIArrayType{
   372  		SizeInBits:  uint64(d.sizes.Sizeof(t) * 8),
   373  		AlignInBits: uint64(d.sizes.Alignof(t) * 8),
   374  		ElementType: d.DIType(t.Elem()),
   375  		Subscripts:  []llvm.DISubrange{{Count: t.Len()}},
   376  	})
   377  }
   378  
   379  func (d *DIBuilder) descriptorSlice(t *types.Slice, name string) llvm.Metadata {
   380  	sliceStruct := types.NewStruct([]*types.Var{
   381  		types.NewVar(0, nil, "ptr", types.NewPointer(t.Elem())),
   382  		types.NewVar(0, nil, "len", types.Typ[types.Int]),
   383  		types.NewVar(0, nil, "cap", types.Typ[types.Int]),
   384  	}, nil)
   385  	return d.typeDebugDescriptor(sliceStruct, name)
   386  }
   387  
   388  func (d *DIBuilder) descriptorMap(t *types.Map, name string) llvm.Metadata {
   389  	// FIXME: This should be DW_TAG_pointer_type to __go_map.
   390  	return d.descriptorBasic(types.Typ[types.Uintptr], name)
   391  }
   392  
   393  func (d *DIBuilder) descriptorChan(t *types.Chan, name string) llvm.Metadata {
   394  	// FIXME: This should be DW_TAG_pointer_type to __go_channel.
   395  	return d.descriptorBasic(types.Typ[types.Uintptr], name)
   396  }
   397  
   398  func (d *DIBuilder) descriptorInterface(t *types.Interface, name string) llvm.Metadata {
   399  	ifaceStruct := types.NewStruct([]*types.Var{
   400  		types.NewVar(0, nil, "type", types.NewPointer(types.Typ[types.Uint8])),
   401  		types.NewVar(0, nil, "data", types.NewPointer(types.Typ[types.Uint8])),
   402  	}, nil)
   403  	return d.typeDebugDescriptor(ifaceStruct, name)
   404  }
   405  
   406  func (d *DIBuilder) descriptorSignature(t *types.Signature, name string) llvm.Metadata {
   407  	// If there's a receiver change the receiver to an
   408  	// additional (first) parameter, and take the value of
   409  	// the resulting signature instead.
   410  	if recv := t.Recv(); recv != nil {
   411  		params := t.Params()
   412  		paramvars := make([]*types.Var, int(params.Len()+1))
   413  		paramvars[0] = recv
   414  		for i := 0; i < int(params.Len()); i++ {
   415  			paramvars[i+1] = params.At(i)
   416  		}
   417  		params = types.NewTuple(paramvars...)
   418  		t := types.NewSignature(nil, nil, params, t.Results(), t.Variadic())
   419  		return d.typeDebugDescriptor(t, name)
   420  	}
   421  	if dt, ok := d.types.At(t).(llvm.Metadata); ok {
   422  		return dt
   423  	}
   424  
   425  	var returnType llvm.Metadata
   426  	results := t.Results()
   427  	switch n := results.Len(); n {
   428  	case 0:
   429  		returnType = d.DIType(nil) // void
   430  	case 1:
   431  		returnType = d.DIType(results.At(0).Type())
   432  	default:
   433  		fields := make([]*types.Var, results.Len())
   434  		for i := range fields {
   435  			f := results.At(i)
   436  			// Structs may not have multiple fields
   437  			// with the same name, excepting "_".
   438  			if f.Name() == "" {
   439  				f = types.NewVar(f.Pos(), f.Pkg(), "_", f.Type())
   440  			}
   441  			fields[i] = f
   442  		}
   443  		returnType = d.typeDebugDescriptor(types.NewStruct(fields, nil), "")
   444  	}
   445  
   446  	var paramTypes []llvm.Metadata
   447  	params := t.Params()
   448  	if params != nil && params.Len() > 0 {
   449  		paramTypes = make([]llvm.Metadata, params.Len()+1)
   450  		paramTypes[0] = returnType
   451  		for i := range paramTypes[1:] {
   452  			paramTypes[i+1] = d.DIType(params.At(i).Type())
   453  		}
   454  	} else {
   455  		paramTypes = []llvm.Metadata{returnType}
   456  	}
   457  
   458  	// TODO(axw) get position of type definition for File field
   459  	return d.builder.CreateSubroutineType(llvm.DISubroutineType{
   460  		Parameters: paramTypes,
   461  	})
   462  }