github.com/axw/llgo@v0.0.0-20160805011314-95b5fe4dca20/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 }) 140 fnptr.SetSubprogram(d.fn) 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 // Value creates an llvm.dbg.value call for the specified register value. 151 func (d *DIBuilder) Value(b llvm.Builder, v ssa.Value, llv llvm.Value, paramIndex int) { 152 // TODO(axw) 153 } 154 155 // SetLocation sets the current debug location. 156 func (d *DIBuilder) SetLocation(b llvm.Builder, pos token.Pos) { 157 position := d.fset.Position(pos) 158 d.lb = llvm.Metadata{} 159 if position.Filename != d.fnFile && position.Filename != "" { 160 // This can happen rarely, e.g. in init functions. 161 diFile := d.builder.CreateFile(d.remapFilePath(position.Filename), "") 162 d.lb = d.builder.CreateLexicalBlockFile(d.scope(), diFile, 0) 163 } 164 b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), d.scope(), llvm.Metadata{}) 165 } 166 167 // Finalize must be called after all compilation units are translated, 168 // generating the final debug metadata for the module. 169 func (d *DIBuilder) Finalize() { 170 d.module.AddNamedMetadataOperand( 171 "llvm.module.flags", 172 llvm.GlobalContext().MDNode([]llvm.Metadata{ 173 llvm.ConstInt(llvm.Int32Type(), 2, false).ConstantAsMetadata(), // Warn on mismatch 174 llvm.GlobalContext().MDString("Dwarf Version"), 175 llvm.ConstInt(llvm.Int32Type(), 4, false).ConstantAsMetadata(), 176 }), 177 ) 178 d.module.AddNamedMetadataOperand( 179 "llvm.module.flags", 180 llvm.GlobalContext().MDNode([]llvm.Metadata{ 181 llvm.ConstInt(llvm.Int32Type(), 1, false).ConstantAsMetadata(), // Error on mismatch 182 llvm.GlobalContext().MDString("Debug Info Version"), 183 llvm.ConstInt(llvm.Int32Type(), 3, false).ConstantAsMetadata(), 184 }), 185 ) 186 d.builder.Finalize() 187 } 188 189 // DIType maps a Go type to DIType debug metadata value. 190 func (d *DIBuilder) DIType(t types.Type) llvm.Metadata { 191 return d.typeDebugDescriptor(t, types.TypeString(nil, t)) 192 } 193 194 func (d *DIBuilder) typeDebugDescriptor(t types.Type, name string) llvm.Metadata { 195 // Signature needs to be handled specially, to preprocess 196 // methods, moving the receiver to the parameter list. 197 if t, ok := t.(*types.Signature); ok { 198 return d.descriptorSignature(t, name) 199 } 200 if t == nil { 201 if d.voidType.C == nil { 202 d.voidType = d.builder.CreateBasicType(llvm.DIBasicType{Name: "void"}) 203 } 204 return d.voidType 205 } 206 if dt, ok := d.types.At(t).(llvm.Metadata); ok { 207 return dt 208 } 209 dt := d.descriptor(t, name) 210 d.types.Set(t, dt) 211 return dt 212 } 213 214 func (d *DIBuilder) descriptor(t types.Type, name string) llvm.Metadata { 215 switch t := t.(type) { 216 case *types.Basic: 217 return d.descriptorBasic(t, name) 218 case *types.Pointer: 219 return d.descriptorPointer(t) 220 case *types.Struct: 221 return d.descriptorStruct(t, name) 222 case *types.Named: 223 return d.descriptorNamed(t) 224 case *types.Array: 225 return d.descriptorArray(t, name) 226 case *types.Slice: 227 return d.descriptorSlice(t, name) 228 case *types.Map: 229 return d.descriptorMap(t, name) 230 case *types.Chan: 231 return d.descriptorChan(t, name) 232 case *types.Interface: 233 return d.descriptorInterface(t, name) 234 default: 235 panic(fmt.Sprintf("unhandled type: %T", t)) 236 } 237 } 238 239 func (d *DIBuilder) descriptorBasic(t *types.Basic, name string) llvm.Metadata { 240 switch t.Kind() { 241 case types.String: 242 return d.typeDebugDescriptor(types.NewStruct([]*types.Var{ 243 types.NewVar(0, nil, "ptr", types.NewPointer(types.Typ[types.Uint8])), 244 types.NewVar(0, nil, "len", types.Typ[types.Int]), 245 }, nil), name) 246 case types.UnsafePointer: 247 return d.builder.CreateBasicType(llvm.DIBasicType{ 248 Name: name, 249 SizeInBits: uint64(d.sizes.Sizeof(t) * 8), 250 AlignInBits: uint64(d.sizes.Alignof(t) * 8), 251 Encoding: llvm.DW_ATE_unsigned, 252 }) 253 default: 254 bt := llvm.DIBasicType{ 255 Name: t.String(), 256 SizeInBits: uint64(d.sizes.Sizeof(t) * 8), 257 AlignInBits: uint64(d.sizes.Alignof(t) * 8), 258 } 259 switch bi := t.Info(); { 260 case bi&types.IsBoolean != 0: 261 bt.Encoding = llvm.DW_ATE_boolean 262 case bi&types.IsUnsigned != 0: 263 bt.Encoding = llvm.DW_ATE_unsigned 264 case bi&types.IsInteger != 0: 265 bt.Encoding = llvm.DW_ATE_signed 266 case bi&types.IsFloat != 0: 267 bt.Encoding = llvm.DW_ATE_float 268 case bi&types.IsComplex != 0: 269 bt.Encoding = llvm.DW_ATE_imaginary_float 270 case bi&types.IsUnsigned != 0: 271 bt.Encoding = llvm.DW_ATE_unsigned 272 default: 273 panic(fmt.Sprintf("unhandled: %#v", t)) 274 } 275 return d.builder.CreateBasicType(bt) 276 } 277 } 278 279 func (d *DIBuilder) descriptorPointer(t *types.Pointer) llvm.Metadata { 280 return d.builder.CreatePointerType(llvm.DIPointerType{ 281 Pointee: d.DIType(t.Elem()), 282 SizeInBits: uint64(d.sizes.Sizeof(t) * 8), 283 AlignInBits: uint64(d.sizes.Alignof(t) * 8), 284 }) 285 } 286 287 func (d *DIBuilder) descriptorStruct(t *types.Struct, name string) llvm.Metadata { 288 fields := make([]*types.Var, t.NumFields()) 289 for i := range fields { 290 fields[i] = t.Field(i) 291 } 292 offsets := d.sizes.Offsetsof(fields) 293 members := make([]llvm.Metadata, len(fields)) 294 for i, f := range fields { 295 // TODO(axw) file/line where member is defined. 296 t := f.Type() 297 members[i] = d.builder.CreateMemberType(d.cu, llvm.DIMemberType{ 298 Name: f.Name(), 299 Type: d.DIType(t), 300 SizeInBits: uint64(d.sizes.Sizeof(t) * 8), 301 AlignInBits: uint64(d.sizes.Alignof(t) * 8), 302 OffsetInBits: uint64(offsets[i] * 8), 303 }) 304 } 305 // TODO(axw) file/line where struct is defined. 306 return d.builder.CreateStructType(d.cu, llvm.DIStructType{ 307 Name: name, 308 SizeInBits: uint64(d.sizes.Sizeof(t) * 8), 309 AlignInBits: uint64(d.sizes.Alignof(t) * 8), 310 Elements: members, 311 }) 312 } 313 314 func (d *DIBuilder) descriptorNamed(t *types.Named) llvm.Metadata { 315 var diFile llvm.Metadata 316 var line int 317 if file := d.fset.File(t.Obj().Pos()); file != nil { 318 line = file.Line(t.Obj().Pos()) 319 diFile = d.getFile(file) 320 } 321 322 // Create a placeholder for the named type, to terminate cycles. 323 name := t.Obj().Name() 324 placeholder := d.builder.CreateReplaceableCompositeType(d.scope(), llvm.DIReplaceableCompositeType{ 325 Tag: dwarf.TagStructType, 326 Name: name, 327 File: diFile, 328 Line: line, 329 }) 330 d.types.Set(t, placeholder) 331 332 typedef := d.builder.CreateTypedef(llvm.DITypedef{ 333 Type: d.DIType(t.Underlying()), 334 Name: name, 335 File: diFile, 336 Line: line, 337 }) 338 placeholder.ReplaceAllUsesWith(typedef) 339 return typedef 340 } 341 342 func (d *DIBuilder) descriptorArray(t *types.Array, name string) llvm.Metadata { 343 return d.builder.CreateArrayType(llvm.DIArrayType{ 344 SizeInBits: uint64(d.sizes.Sizeof(t) * 8), 345 AlignInBits: uint64(d.sizes.Alignof(t) * 8), 346 ElementType: d.DIType(t.Elem()), 347 Subscripts: []llvm.DISubrange{{Count: t.Len()}}, 348 }) 349 } 350 351 func (d *DIBuilder) descriptorSlice(t *types.Slice, name string) llvm.Metadata { 352 sliceStruct := types.NewStruct([]*types.Var{ 353 types.NewVar(0, nil, "ptr", types.NewPointer(t.Elem())), 354 types.NewVar(0, nil, "len", types.Typ[types.Int]), 355 types.NewVar(0, nil, "cap", types.Typ[types.Int]), 356 }, nil) 357 return d.typeDebugDescriptor(sliceStruct, name) 358 } 359 360 func (d *DIBuilder) descriptorMap(t *types.Map, name string) llvm.Metadata { 361 // FIXME: This should be DW_TAG_pointer_type to __go_map. 362 return d.descriptorBasic(types.Typ[types.Uintptr], name) 363 } 364 365 func (d *DIBuilder) descriptorChan(t *types.Chan, name string) llvm.Metadata { 366 // FIXME: This should be DW_TAG_pointer_type to __go_channel. 367 return d.descriptorBasic(types.Typ[types.Uintptr], name) 368 } 369 370 func (d *DIBuilder) descriptorInterface(t *types.Interface, name string) llvm.Metadata { 371 ifaceStruct := types.NewStruct([]*types.Var{ 372 types.NewVar(0, nil, "type", types.NewPointer(types.Typ[types.Uint8])), 373 types.NewVar(0, nil, "data", types.NewPointer(types.Typ[types.Uint8])), 374 }, nil) 375 return d.typeDebugDescriptor(ifaceStruct, name) 376 } 377 378 func (d *DIBuilder) descriptorSignature(t *types.Signature, name string) llvm.Metadata { 379 // If there's a receiver change the receiver to an 380 // additional (first) parameter, and take the value of 381 // the resulting signature instead. 382 if recv := t.Recv(); recv != nil { 383 params := t.Params() 384 paramvars := make([]*types.Var, int(params.Len()+1)) 385 paramvars[0] = recv 386 for i := 0; i < int(params.Len()); i++ { 387 paramvars[i+1] = params.At(i) 388 } 389 params = types.NewTuple(paramvars...) 390 t := types.NewSignature(nil, nil, params, t.Results(), t.Variadic()) 391 return d.typeDebugDescriptor(t, name) 392 } 393 if dt, ok := d.types.At(t).(llvm.Metadata); ok { 394 return dt 395 } 396 397 var returnType llvm.Metadata 398 results := t.Results() 399 switch n := results.Len(); n { 400 case 0: 401 returnType = d.DIType(nil) // void 402 case 1: 403 returnType = d.DIType(results.At(0).Type()) 404 default: 405 fields := make([]*types.Var, results.Len()) 406 for i := range fields { 407 f := results.At(i) 408 // Structs may not have multiple fields 409 // with the same name, excepting "_". 410 if f.Name() == "" { 411 f = types.NewVar(f.Pos(), f.Pkg(), "_", f.Type()) 412 } 413 fields[i] = f 414 } 415 returnType = d.typeDebugDescriptor(types.NewStruct(fields, nil), "") 416 } 417 418 var paramTypes []llvm.Metadata 419 params := t.Params() 420 if params != nil && params.Len() > 0 { 421 paramTypes = make([]llvm.Metadata, params.Len()+1) 422 paramTypes[0] = returnType 423 for i := range paramTypes[1:] { 424 paramTypes[i+1] = d.DIType(params.At(i).Type()) 425 } 426 } else { 427 paramTypes = []llvm.Metadata{returnType} 428 } 429 430 // TODO(axw) get position of type definition for File field 431 return d.builder.CreateSubroutineType(llvm.DISubroutineType{ 432 Parameters: paramTypes, 433 }) 434 }