blob: b8c6bf6c90066fd09fd5b9f180cc621ed42f8e21 [file] [log] [blame]
Peter Collingbournead9841e2014-11-27 00:06:42 +00001//===- 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
14package debug
15
16import (
17 "debug/dwarf"
18 "fmt"
19 "go/token"
20 "os"
21 "strings"
22
Peter Collingbourne56109b72015-01-13 20:45:08 +000023 "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"
Peter Collingbournead9841e2014-11-27 00:06:42 +000026
27 "llvm.org/llvm/bindings/go/llvm"
28)
29
30const (
31 // non-standard debug metadata tags
32 tagAutoVariable dwarf.Tag = 0x100
33 tagArgVariable dwarf.Tag = 0x101
34)
35
36type PrefixMap struct {
37 Source, Replacement string
38}
39
40// DIBuilder builds debug metadata for Go programs.
41type DIBuilder struct {
42 // builder is the current builder; there is one per CU.
43 builder *llvm.DIBuilder
44 module llvm.Module
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +000045 files map[*token.File]llvm.Metadata
46 cu, fn, lb llvm.Metadata
Peter Collingbournead9841e2014-11-27 00:06:42 +000047 fnFile string
Peter Collingbournead9841e2014-11-27 00:06:42 +000048 sizes types.Sizes
49 fset *token.FileSet
50 prefixMaps []PrefixMap
51 types typeutil.Map
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +000052 voidType llvm.Metadata
Peter Collingbournead9841e2014-11-27 00:06:42 +000053}
54
55// NewDIBuilder creates a new debug information builder.
56func NewDIBuilder(sizes types.Sizes, module llvm.Module, fset *token.FileSet, prefixMaps []PrefixMap) *DIBuilder {
57 var d DIBuilder
58 d.module = module
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +000059 d.files = make(map[*token.File]llvm.Metadata)
Peter Collingbournead9841e2014-11-27 00:06:42 +000060 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.
69func (d *DIBuilder) Destroy() {
70 d.builder.Destroy()
71}
72
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +000073func (d *DIBuilder) scope() llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +000074 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
83func (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
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +000092func (d *DIBuilder) getFile(file *token.File) llvm.Metadata {
93 if diFile := d.files[file]; diFile.C != nil {
Peter Collingbournead9841e2014-11-27 00:06:42 +000094 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).
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000104func (d *DIBuilder) createCompileUnit() llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000105 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.
124func (d *DIBuilder) PushFunction(fnptr llvm.Value, sig *types.Signature, pos token.Pos) {
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000125 var diFile llvm.Metadata
Peter Collingbournead9841e2014-11-27 00:06:42 +0000126 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.
144func (d *DIBuilder) PopFunction() {
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000145 d.lb = llvm.Metadata{}
146 d.fn = llvm.Metadata{}
Peter Collingbournead9841e2014-11-27 00:06:42 +0000147 d.fnFile = ""
148}
149
150// Declare creates an llvm.dbg.declare call for the specified function
151// parameter or local variable.
152func (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 }
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000157 var diFile llvm.Metadata
Peter Collingbournead9841e2014-11-27 00:06:42 +0000158 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.
176func (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.
181func (d *DIBuilder) SetLocation(b llvm.Builder, pos token.Pos) {
182 if !pos.IsValid() {
183 return
184 }
185 position := d.fset.Position(pos)
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000186 d.lb = llvm.Metadata{}
Peter Collingbournead9841e2014-11-27 00:06:42 +0000187 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 }
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000192 b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), d.scope(), llvm.Metadata{})
Peter Collingbournead9841e2014-11-27 00:06:42 +0000193}
194
195// Finalize must be called after all compilation units are translated,
196// generating the final debug metadata for the module.
197func (d *DIBuilder) Finalize() {
198 d.module.AddNamedMetadataOperand(
199 "llvm.module.flags",
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000200 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(),
Peter Collingbournead9841e2014-11-27 00:06:42 +0000204 }),
205 )
206 d.module.AddNamedMetadataOperand(
207 "llvm.module.flags",
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000208 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(),
Peter Collingbournead9841e2014-11-27 00:06:42 +0000212 }),
213 )
214 d.builder.Finalize()
215}
216
217// DIType maps a Go type to DIType debug metadata value.
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000218func (d *DIBuilder) DIType(t types.Type) llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000219 return d.typeDebugDescriptor(t, types.TypeString(nil, t))
220}
221
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000222func (d *DIBuilder) typeDebugDescriptor(t types.Type, name string) llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000223 // 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 {
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000229 if d.voidType.C == nil {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000230 d.voidType = d.builder.CreateBasicType(llvm.DIBasicType{Name: "void"})
231 }
232 return d.voidType
233 }
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000234 if dt, ok := d.types.At(t).(llvm.Metadata); ok {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000235 return dt
236 }
237 dt := d.descriptor(t, name)
238 d.types.Set(t, dt)
239 return dt
240}
241
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000242func (d *DIBuilder) descriptor(t types.Type, name string) llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000243 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
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000267func (d *DIBuilder) descriptorBasic(t *types.Basic, name string) llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000268 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
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000307func (d *DIBuilder) descriptorPointer(t *types.Pointer) llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000308 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
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000315func (d *DIBuilder) descriptorStruct(t *types.Struct, name string) llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000316 fields := make([]*types.Var, t.NumFields())
317 for i := range fields {
318 fields[i] = t.Field(i)
319 }
320 offsets := d.sizes.Offsetsof(fields)
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000321 members := make([]llvm.Metadata, len(fields))
Peter Collingbournead9841e2014-11-27 00:06:42 +0000322 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
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000342func (d *DIBuilder) descriptorNamed(t *types.Named) llvm.Metadata {
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000343 var diFile llvm.Metadata
Peter Collingbournead9841e2014-11-27 00:06:42 +0000344 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 }
Andrew Wilkinsac151692015-03-02 12:42:45 +0000349
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
Peter Collingbournead9841e2014-11-27 00:06:42 +0000360 typedef := d.builder.CreateTypedef(llvm.DITypedef{
361 Type: d.DIType(t.Underlying()),
Andrew Wilkinsac151692015-03-02 12:42:45 +0000362 Name: name,
Peter Collingbournead9841e2014-11-27 00:06:42 +0000363 File: diFile,
364 Line: line,
365 })
366 placeholder.ReplaceAllUsesWith(typedef)
367 return typedef
368}
369
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000370func (d *DIBuilder) descriptorArray(t *types.Array, name string) llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000371 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
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000379func (d *DIBuilder) descriptorSlice(t *types.Slice, name string) llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000380 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
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000388func (d *DIBuilder) descriptorMap(t *types.Map, name string) llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000389 // FIXME: This should be DW_TAG_pointer_type to __go_map.
390 return d.descriptorBasic(types.Typ[types.Uintptr], name)
391}
392
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000393func (d *DIBuilder) descriptorChan(t *types.Chan, name string) llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000394 // FIXME: This should be DW_TAG_pointer_type to __go_channel.
395 return d.descriptorBasic(types.Typ[types.Uintptr], name)
396}
397
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000398func (d *DIBuilder) descriptorInterface(t *types.Interface, name string) llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000399 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
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000406func (d *DIBuilder) descriptorSignature(t *types.Signature, name string) llvm.Metadata {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000407 // 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 }
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000421 if dt, ok := d.types.At(t).(llvm.Metadata); ok {
Peter Collingbournead9841e2014-11-27 00:06:42 +0000422 return dt
423 }
424
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000425 var returnType llvm.Metadata
Peter Collingbournead9841e2014-11-27 00:06:42 +0000426 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
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000446 var paramTypes []llvm.Metadata
Peter Collingbournead9841e2014-11-27 00:06:42 +0000447 params := t.Params()
448 if params != nil && params.Len() > 0 {
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000449 paramTypes = make([]llvm.Metadata, params.Len()+1)
Peter Collingbournead9841e2014-11-27 00:06:42 +0000450 paramTypes[0] = returnType
451 for i := range paramTypes[1:] {
452 paramTypes[i+1] = d.DIType(params.At(i).Type())
453 }
454 } else {
Peter Collingbourne8bcc05d2014-12-13 02:26:00 +0000455 paramTypes = []llvm.Metadata{returnType}
Peter Collingbournead9841e2014-11-27 00:06:42 +0000456 }
457
458 // TODO(axw) get position of type definition for File field
459 return d.builder.CreateSubroutineType(llvm.DISubroutineType{
460 Parameters: paramTypes,
461 })
462}