From 0c73d56861e957f173fe24b000284dc720924afc Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sun, 26 Jan 2020 18:59:59 +0100 Subject: [PATCH] compiler: add debug info for local variables Local variables aren't scoped yet and not all are included, but this is a start. To use it, run `info locals` in GDB. --- compiler/compiler.go | 82 ++++++++++++++++++++++++++++++++++++-------- go.mod | 3 +- go.sum | 11 ++++++ 3 files changed, 81 insertions(+), 15 deletions(-) diff --git a/compiler/compiler.go b/compiler/compiler.go index ebfcc128..dfe3dd77 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -92,6 +92,7 @@ type Frame struct { taskHandle llvm.Value deferPtr llvm.Value difunc llvm.Metadata + dilocals map[*types.Var]llvm.Metadata allDeferFuncs []interface{} deferFuncs map[*ir.Function]int deferInvokeFuncs map[string]int @@ -708,10 +709,51 @@ func (c *Compiler) createDIType(typ types.Type) llvm.Metadata { } } +// getLocalVariable returns a debug info entry for a local variable, which may +// either be a parameter or a regular variable. It will create a new metadata +// entry if there isn't one for the variable yet. +func (c *Compiler) getLocalVariable(frame *Frame, variable *types.Var) llvm.Metadata { + if dilocal, ok := frame.dilocals[variable]; ok { + // DILocalVariable was already created, return it directly. + return dilocal + } + + pos := c.ir.Program.Fset.Position(variable.Pos()) + + // Check whether this is a function parameter. + for i, param := range frame.fn.Params { + if param.Object().(*types.Var) == variable { + // Yes it is, create it as a function parameter. + dilocal := c.dibuilder.CreateParameterVariable(frame.difunc, llvm.DIParameterVariable{ + Name: param.Name(), + File: c.getDIFile(pos.Filename), + Line: pos.Line, + Type: c.getDIType(variable.Type()), + AlwaysPreserve: true, + ArgNo: i + 1, + }) + frame.dilocals[variable] = dilocal + return dilocal + } + } + + // No, it's not a parameter. Create a regular (auto) variable. + dilocal := c.dibuilder.CreateAutoVariable(frame.difunc, llvm.DIAutoVariable{ + Name: variable.Name(), + File: c.getDIFile(pos.Filename), + Line: pos.Line, + Type: c.getDIType(variable.Type()), + AlwaysPreserve: true, + }) + frame.dilocals[variable] = dilocal + return dilocal +} + func (c *Compiler) parseFuncDecl(f *ir.Function) *Frame { frame := &Frame{ fn: f, locals: make(map[ssa.Value]llvm.Value), + dilocals: make(map[*types.Var]llvm.Metadata), blockEntries: make(map[*ssa.BasicBlock]llvm.BasicBlock), blockExits: make(map[*ssa.BasicBlock]llvm.BasicBlock), } @@ -783,11 +825,11 @@ func (c *Compiler) attachDebugInfoRaw(f *ir.Function, llvmFn llvm.Value, suffix, diparams = append(diparams, c.getDIType(param.Type())) } diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{ - File: c.difiles[filename], + File: c.getDIFile(filename), Parameters: diparams, Flags: 0, // ? }) - difunc := c.dibuilder.CreateFunction(c.difiles[filename], llvm.DIFunction{ + difunc := c.dibuilder.CreateFunction(c.getDIFile(filename), llvm.DIFunction{ Name: f.RelString(nil) + suffix, LinkageName: f.LinkName() + suffix, File: c.getDIFile(filename), @@ -872,7 +914,7 @@ func (c *Compiler) parseFunc(frame *Frame) { // Load function parameters llvmParamIndex := 0 - for i, param := range frame.fn.Params { + for _, param := range frame.fn.Params { llvmType := c.getLLVMType(param.Type()) fields := make([]llvm.Value, 0, 1) for range c.expandFormalParamType(llvmType) { @@ -883,16 +925,7 @@ func (c *Compiler) parseFunc(frame *Frame) { // Add debug information to this parameter (if available) if c.Debug() && frame.fn.Syntax() != nil { - pos := c.ir.Program.Fset.Position(frame.fn.Syntax().Pos()) - diType := c.getDIType(param.Type()) - dbgParam := c.dibuilder.CreateParameterVariable(frame.difunc, llvm.DIParameterVariable{ - Name: param.Name(), - File: c.difiles[pos.Filename], - Line: pos.Line, - Type: diType, - AlwaysPreserve: true, - ArgNo: i + 1, - }) + dbgParam := c.getLocalVariable(frame, param.Object().(*types.Var)) loc := c.builder.GetCurrentDebugLocation() if len(fields) == 1 { expr := c.dibuilder.CreateExpression(nil) @@ -950,7 +983,28 @@ func (c *Compiler) parseFunc(frame *Frame) { c.builder.SetInsertPointAtEnd(frame.blockEntries[block]) frame.currentBlock = block for _, instr := range block.Instrs { - if _, ok := instr.(*ssa.DebugRef); ok { + if instr, ok := instr.(*ssa.DebugRef); ok { + if !c.Debug() { + continue + } + object := instr.Object() + variable, ok := object.(*types.Var) + if !ok { + // Not a local variable. + continue + } + if instr.IsAddr { + // TODO, this may happen for *ssa.Alloc and *ssa.FieldAddr + // for example. + continue + } + dbgVar := c.getLocalVariable(frame, variable) + pos := c.ir.Program.Fset.Position(instr.Pos()) + c.dibuilder.InsertValueAtEnd(c.getValue(frame, instr.X), dbgVar, c.dibuilder.CreateExpression(nil), llvm.DebugLoc{ + Line: uint(pos.Line), + Col: uint(pos.Column), + Scope: frame.difunc, + }, c.builder.GetInsertBlock()) continue } if c.DumpSSA() { diff --git a/go.mod b/go.mod index d9043429..2961aff0 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46 go.bug.st/serial v1.0.0 - golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef + golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2 + google.golang.org/appengine v1.4.0 // indirect tinygo.org/x/go-llvm v0.0.0-20200104190746-1ff21df33566 ) diff --git a/go.sum b/go.sum index 9902c624..415c68bc 100644 --- a/go.sum +++ b/go.sum @@ -13,14 +13,25 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= go.bug.st/serial v1.0.0 h1:ogEPzrllCsnG00EqKRjeYvPRsO7NJW6DqykzkdD6E/k= go.bug.st/serial v1.0.0/go.mod h1:rpXPISGjuNjPTRTcMlxi9lN6LoIPxd1ixVjBd8aSk/Q= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef h1:ymc9FeDom3RIEA3coKokSllBB1hRcMT0tZ1W3Jf9Ids= golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2 h1:0sfSpGSa544Fwnbot3Oxq/U6SXqjty6Jy/3wRhVS7ig= +golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=