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