Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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 | |
Peter Collingbourne | 56109b7 | 2015-01-13 20:45:08 +0000 | [diff] [blame] | 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" |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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 |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 45 | files map[*token.File]llvm.Metadata |
| 46 | cu, fn, lb llvm.Metadata |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 47 | fnFile string |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 48 | sizes types.Sizes |
| 49 | fset *token.FileSet |
| 50 | prefixMaps []PrefixMap |
| 51 | types typeutil.Map |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 52 | voidType llvm.Metadata |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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 |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 59 | d.files = make(map[*token.File]llvm.Metadata) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 73 | func (d *DIBuilder) scope() llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 92 | func (d *DIBuilder) getFile(file *token.File) llvm.Metadata { |
| 93 | if diFile := d.files[file]; diFile.C != nil { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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). |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 104 | func (d *DIBuilder) createCompileUnit() llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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) { |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 125 | var diFile llvm.Metadata |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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, |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 139 | }) |
Peter Collingbourne | 8324851 | 2015-11-05 22:04:20 +0000 | [diff] [blame] | 140 | fnptr.SetSubprogram(d.fn) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 141 | } |
| 142 | |
| 143 | // PopFunction pops the previously pushed function off the scope stack. |
| 144 | func (d *DIBuilder) PopFunction() { |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 145 | d.lb = llvm.Metadata{} |
| 146 | d.fn = llvm.Metadata{} |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 147 | d.fnFile = "" |
| 148 | } |
| 149 | |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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) { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 157 | position := d.fset.Position(pos) |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 158 | d.lb = llvm.Metadata{} |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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 | } |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 164 | b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), d.scope(), llvm.Metadata{}) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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", |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 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(), |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 176 | }), |
| 177 | ) |
| 178 | d.module.AddNamedMetadataOperand( |
| 179 | "llvm.module.flags", |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 180 | llvm.GlobalContext().MDNode([]llvm.Metadata{ |
| 181 | llvm.ConstInt(llvm.Int32Type(), 1, false).ConstantAsMetadata(), // Error on mismatch |
| 182 | llvm.GlobalContext().MDString("Debug Info Version"), |
Andrew Wilkins | 0f432aa | 2016-03-23 23:09:00 +0000 | [diff] [blame] | 183 | llvm.ConstInt(llvm.Int32Type(), 3, false).ConstantAsMetadata(), |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 184 | }), |
| 185 | ) |
| 186 | d.builder.Finalize() |
| 187 | } |
| 188 | |
| 189 | // DIType maps a Go type to DIType debug metadata value. |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 190 | func (d *DIBuilder) DIType(t types.Type) llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 191 | return d.typeDebugDescriptor(t, types.TypeString(nil, t)) |
| 192 | } |
| 193 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 194 | func (d *DIBuilder) typeDebugDescriptor(t types.Type, name string) llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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 { |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 201 | if d.voidType.C == nil { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 202 | d.voidType = d.builder.CreateBasicType(llvm.DIBasicType{Name: "void"}) |
| 203 | } |
| 204 | return d.voidType |
| 205 | } |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 206 | if dt, ok := d.types.At(t).(llvm.Metadata); ok { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 207 | return dt |
| 208 | } |
| 209 | dt := d.descriptor(t, name) |
| 210 | d.types.Set(t, dt) |
| 211 | return dt |
| 212 | } |
| 213 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 214 | func (d *DIBuilder) descriptor(t types.Type, name string) llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 239 | func (d *DIBuilder) descriptorBasic(t *types.Basic, name string) llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 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), |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 250 | Encoding: llvm.DW_ATE_unsigned, |
| 251 | }) |
| 252 | default: |
| 253 | bt := llvm.DIBasicType{ |
| 254 | Name: t.String(), |
| 255 | SizeInBits: uint64(d.sizes.Sizeof(t) * 8), |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 256 | } |
| 257 | switch bi := t.Info(); { |
| 258 | case bi&types.IsBoolean != 0: |
| 259 | bt.Encoding = llvm.DW_ATE_boolean |
| 260 | case bi&types.IsUnsigned != 0: |
| 261 | bt.Encoding = llvm.DW_ATE_unsigned |
| 262 | case bi&types.IsInteger != 0: |
| 263 | bt.Encoding = llvm.DW_ATE_signed |
| 264 | case bi&types.IsFloat != 0: |
| 265 | bt.Encoding = llvm.DW_ATE_float |
| 266 | case bi&types.IsComplex != 0: |
| 267 | bt.Encoding = llvm.DW_ATE_imaginary_float |
| 268 | case bi&types.IsUnsigned != 0: |
| 269 | bt.Encoding = llvm.DW_ATE_unsigned |
| 270 | default: |
| 271 | panic(fmt.Sprintf("unhandled: %#v", t)) |
| 272 | } |
| 273 | return d.builder.CreateBasicType(bt) |
| 274 | } |
| 275 | } |
| 276 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 277 | func (d *DIBuilder) descriptorPointer(t *types.Pointer) llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 278 | return d.builder.CreatePointerType(llvm.DIPointerType{ |
| 279 | Pointee: d.DIType(t.Elem()), |
| 280 | SizeInBits: uint64(d.sizes.Sizeof(t) * 8), |
Meador Inge | 7695d89 | 2016-12-06 04:00:12 +0000 | [diff] [blame] | 281 | AlignInBits: uint32(d.sizes.Alignof(t) * 8), |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 282 | }) |
| 283 | } |
| 284 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 285 | func (d *DIBuilder) descriptorStruct(t *types.Struct, name string) llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 286 | fields := make([]*types.Var, t.NumFields()) |
| 287 | for i := range fields { |
| 288 | fields[i] = t.Field(i) |
| 289 | } |
| 290 | offsets := d.sizes.Offsetsof(fields) |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 291 | members := make([]llvm.Metadata, len(fields)) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 292 | for i, f := range fields { |
| 293 | // TODO(axw) file/line where member is defined. |
| 294 | t := f.Type() |
| 295 | members[i] = d.builder.CreateMemberType(d.cu, llvm.DIMemberType{ |
| 296 | Name: f.Name(), |
| 297 | Type: d.DIType(t), |
| 298 | SizeInBits: uint64(d.sizes.Sizeof(t) * 8), |
Meador Inge | 7695d89 | 2016-12-06 04:00:12 +0000 | [diff] [blame] | 299 | AlignInBits: uint32(d.sizes.Alignof(t) * 8), |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 300 | OffsetInBits: uint64(offsets[i] * 8), |
| 301 | }) |
| 302 | } |
| 303 | // TODO(axw) file/line where struct is defined. |
| 304 | return d.builder.CreateStructType(d.cu, llvm.DIStructType{ |
| 305 | Name: name, |
| 306 | SizeInBits: uint64(d.sizes.Sizeof(t) * 8), |
Meador Inge | 7695d89 | 2016-12-06 04:00:12 +0000 | [diff] [blame] | 307 | AlignInBits: uint32(d.sizes.Alignof(t) * 8), |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 308 | Elements: members, |
| 309 | }) |
| 310 | } |
| 311 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 312 | func (d *DIBuilder) descriptorNamed(t *types.Named) llvm.Metadata { |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 313 | var diFile llvm.Metadata |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 314 | var line int |
| 315 | if file := d.fset.File(t.Obj().Pos()); file != nil { |
| 316 | line = file.Line(t.Obj().Pos()) |
| 317 | diFile = d.getFile(file) |
| 318 | } |
Andrew Wilkins | ac15169 | 2015-03-02 12:42:45 +0000 | [diff] [blame] | 319 | |
| 320 | // Create a placeholder for the named type, to terminate cycles. |
| 321 | name := t.Obj().Name() |
| 322 | placeholder := d.builder.CreateReplaceableCompositeType(d.scope(), llvm.DIReplaceableCompositeType{ |
| 323 | Tag: dwarf.TagStructType, |
| 324 | Name: name, |
| 325 | File: diFile, |
| 326 | Line: line, |
| 327 | }) |
| 328 | d.types.Set(t, placeholder) |
| 329 | |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 330 | typedef := d.builder.CreateTypedef(llvm.DITypedef{ |
| 331 | Type: d.DIType(t.Underlying()), |
Andrew Wilkins | ac15169 | 2015-03-02 12:42:45 +0000 | [diff] [blame] | 332 | Name: name, |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 333 | File: diFile, |
| 334 | Line: line, |
| 335 | }) |
| 336 | placeholder.ReplaceAllUsesWith(typedef) |
| 337 | return typedef |
| 338 | } |
| 339 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 340 | func (d *DIBuilder) descriptorArray(t *types.Array, name string) llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 341 | return d.builder.CreateArrayType(llvm.DIArrayType{ |
| 342 | SizeInBits: uint64(d.sizes.Sizeof(t) * 8), |
Meador Inge | 7695d89 | 2016-12-06 04:00:12 +0000 | [diff] [blame] | 343 | AlignInBits: uint32(d.sizes.Alignof(t) * 8), |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 344 | ElementType: d.DIType(t.Elem()), |
| 345 | Subscripts: []llvm.DISubrange{{Count: t.Len()}}, |
| 346 | }) |
| 347 | } |
| 348 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 349 | func (d *DIBuilder) descriptorSlice(t *types.Slice, name string) llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 350 | sliceStruct := types.NewStruct([]*types.Var{ |
| 351 | types.NewVar(0, nil, "ptr", types.NewPointer(t.Elem())), |
| 352 | types.NewVar(0, nil, "len", types.Typ[types.Int]), |
| 353 | types.NewVar(0, nil, "cap", types.Typ[types.Int]), |
| 354 | }, nil) |
| 355 | return d.typeDebugDescriptor(sliceStruct, name) |
| 356 | } |
| 357 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 358 | func (d *DIBuilder) descriptorMap(t *types.Map, name string) llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 359 | // FIXME: This should be DW_TAG_pointer_type to __go_map. |
| 360 | return d.descriptorBasic(types.Typ[types.Uintptr], name) |
| 361 | } |
| 362 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 363 | func (d *DIBuilder) descriptorChan(t *types.Chan, name string) llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 364 | // FIXME: This should be DW_TAG_pointer_type to __go_channel. |
| 365 | return d.descriptorBasic(types.Typ[types.Uintptr], name) |
| 366 | } |
| 367 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 368 | func (d *DIBuilder) descriptorInterface(t *types.Interface, name string) llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 369 | ifaceStruct := types.NewStruct([]*types.Var{ |
| 370 | types.NewVar(0, nil, "type", types.NewPointer(types.Typ[types.Uint8])), |
| 371 | types.NewVar(0, nil, "data", types.NewPointer(types.Typ[types.Uint8])), |
| 372 | }, nil) |
| 373 | return d.typeDebugDescriptor(ifaceStruct, name) |
| 374 | } |
| 375 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 376 | func (d *DIBuilder) descriptorSignature(t *types.Signature, name string) llvm.Metadata { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 377 | // If there's a receiver change the receiver to an |
| 378 | // additional (first) parameter, and take the value of |
| 379 | // the resulting signature instead. |
| 380 | if recv := t.Recv(); recv != nil { |
| 381 | params := t.Params() |
| 382 | paramvars := make([]*types.Var, int(params.Len()+1)) |
| 383 | paramvars[0] = recv |
| 384 | for i := 0; i < int(params.Len()); i++ { |
| 385 | paramvars[i+1] = params.At(i) |
| 386 | } |
| 387 | params = types.NewTuple(paramvars...) |
| 388 | t := types.NewSignature(nil, nil, params, t.Results(), t.Variadic()) |
| 389 | return d.typeDebugDescriptor(t, name) |
| 390 | } |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 391 | if dt, ok := d.types.At(t).(llvm.Metadata); ok { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 392 | return dt |
| 393 | } |
| 394 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 395 | var returnType llvm.Metadata |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 396 | results := t.Results() |
| 397 | switch n := results.Len(); n { |
| 398 | case 0: |
| 399 | returnType = d.DIType(nil) // void |
| 400 | case 1: |
| 401 | returnType = d.DIType(results.At(0).Type()) |
| 402 | default: |
| 403 | fields := make([]*types.Var, results.Len()) |
| 404 | for i := range fields { |
| 405 | f := results.At(i) |
| 406 | // Structs may not have multiple fields |
| 407 | // with the same name, excepting "_". |
| 408 | if f.Name() == "" { |
| 409 | f = types.NewVar(f.Pos(), f.Pkg(), "_", f.Type()) |
| 410 | } |
| 411 | fields[i] = f |
| 412 | } |
| 413 | returnType = d.typeDebugDescriptor(types.NewStruct(fields, nil), "") |
| 414 | } |
| 415 | |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 416 | var paramTypes []llvm.Metadata |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 417 | params := t.Params() |
| 418 | if params != nil && params.Len() > 0 { |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 419 | paramTypes = make([]llvm.Metadata, params.Len()+1) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 420 | paramTypes[0] = returnType |
| 421 | for i := range paramTypes[1:] { |
| 422 | paramTypes[i+1] = d.DIType(params.At(i).Type()) |
| 423 | } |
| 424 | } else { |
Peter Collingbourne | 8bcc05d | 2014-12-13 02:26:00 +0000 | [diff] [blame] | 425 | paramTypes = []llvm.Metadata{returnType} |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 426 | } |
| 427 | |
| 428 | // TODO(axw) get position of type definition for File field |
| 429 | return d.builder.CreateSubroutineType(llvm.DISubroutineType{ |
| 430 | Parameters: paramTypes, |
| 431 | }) |
| 432 | } |