PageRenderTime 47ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/debug/debug.go

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