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 }