Skip to content

Commit 0c73d56

Browse files
aykevldeadprogram
authored andcommitted
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.
1 parent c8a4994 commit 0c73d56

File tree

3 files changed

+81
-15
lines changed

3 files changed

+81
-15
lines changed

compiler/compiler.go

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ type Frame struct {
9292
taskHandle llvm.Value
9393
deferPtr llvm.Value
9494
difunc llvm.Metadata
95+
dilocals map[*types.Var]llvm.Metadata
9596
allDeferFuncs []interface{}
9697
deferFuncs map[*ir.Function]int
9798
deferInvokeFuncs map[string]int
@@ -708,10 +709,51 @@ func (c *Compiler) createDIType(typ types.Type) llvm.Metadata {
708709
}
709710
}
710711

712+
// getLocalVariable returns a debug info entry for a local variable, which may
713+
// either be a parameter or a regular variable. It will create a new metadata
714+
// entry if there isn't one for the variable yet.
715+
func (c *Compiler) getLocalVariable(frame *Frame, variable *types.Var) llvm.Metadata {
716+
if dilocal, ok := frame.dilocals[variable]; ok {
717+
// DILocalVariable was already created, return it directly.
718+
return dilocal
719+
}
720+
721+
pos := c.ir.Program.Fset.Position(variable.Pos())
722+
723+
// Check whether this is a function parameter.
724+
for i, param := range frame.fn.Params {
725+
if param.Object().(*types.Var) == variable {
726+
// Yes it is, create it as a function parameter.
727+
dilocal := c.dibuilder.CreateParameterVariable(frame.difunc, llvm.DIParameterVariable{
728+
Name: param.Name(),
729+
File: c.getDIFile(pos.Filename),
730+
Line: pos.Line,
731+
Type: c.getDIType(variable.Type()),
732+
AlwaysPreserve: true,
733+
ArgNo: i + 1,
734+
})
735+
frame.dilocals[variable] = dilocal
736+
return dilocal
737+
}
738+
}
739+
740+
// No, it's not a parameter. Create a regular (auto) variable.
741+
dilocal := c.dibuilder.CreateAutoVariable(frame.difunc, llvm.DIAutoVariable{
742+
Name: variable.Name(),
743+
File: c.getDIFile(pos.Filename),
744+
Line: pos.Line,
745+
Type: c.getDIType(variable.Type()),
746+
AlwaysPreserve: true,
747+
})
748+
frame.dilocals[variable] = dilocal
749+
return dilocal
750+
}
751+
711752
func (c *Compiler) parseFuncDecl(f *ir.Function) *Frame {
712753
frame := &Frame{
713754
fn: f,
714755
locals: make(map[ssa.Value]llvm.Value),
756+
dilocals: make(map[*types.Var]llvm.Metadata),
715757
blockEntries: make(map[*ssa.BasicBlock]llvm.BasicBlock),
716758
blockExits: make(map[*ssa.BasicBlock]llvm.BasicBlock),
717759
}
@@ -783,11 +825,11 @@ func (c *Compiler) attachDebugInfoRaw(f *ir.Function, llvmFn llvm.Value, suffix,
783825
diparams = append(diparams, c.getDIType(param.Type()))
784826
}
785827
diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
786-
File: c.difiles[filename],
828+
File: c.getDIFile(filename),
787829
Parameters: diparams,
788830
Flags: 0, // ?
789831
})
790-
difunc := c.dibuilder.CreateFunction(c.difiles[filename], llvm.DIFunction{
832+
difunc := c.dibuilder.CreateFunction(c.getDIFile(filename), llvm.DIFunction{
791833
Name: f.RelString(nil) + suffix,
792834
LinkageName: f.LinkName() + suffix,
793835
File: c.getDIFile(filename),
@@ -872,7 +914,7 @@ func (c *Compiler) parseFunc(frame *Frame) {
872914

873915
// Load function parameters
874916
llvmParamIndex := 0
875-
for i, param := range frame.fn.Params {
917+
for _, param := range frame.fn.Params {
876918
llvmType := c.getLLVMType(param.Type())
877919
fields := make([]llvm.Value, 0, 1)
878920
for range c.expandFormalParamType(llvmType) {
@@ -883,16 +925,7 @@ func (c *Compiler) parseFunc(frame *Frame) {
883925

884926
// Add debug information to this parameter (if available)
885927
if c.Debug() && frame.fn.Syntax() != nil {
886-
pos := c.ir.Program.Fset.Position(frame.fn.Syntax().Pos())
887-
diType := c.getDIType(param.Type())
888-
dbgParam := c.dibuilder.CreateParameterVariable(frame.difunc, llvm.DIParameterVariable{
889-
Name: param.Name(),
890-
File: c.difiles[pos.Filename],
891-
Line: pos.Line,
892-
Type: diType,
893-
AlwaysPreserve: true,
894-
ArgNo: i + 1,
895-
})
928+
dbgParam := c.getLocalVariable(frame, param.Object().(*types.Var))
896929
loc := c.builder.GetCurrentDebugLocation()
897930
if len(fields) == 1 {
898931
expr := c.dibuilder.CreateExpression(nil)
@@ -950,7 +983,28 @@ func (c *Compiler) parseFunc(frame *Frame) {
950983
c.builder.SetInsertPointAtEnd(frame.blockEntries[block])
951984
frame.currentBlock = block
952985
for _, instr := range block.Instrs {
953-
if _, ok := instr.(*ssa.DebugRef); ok {
986+
if instr, ok := instr.(*ssa.DebugRef); ok {
987+
if !c.Debug() {
988+
continue
989+
}
990+
object := instr.Object()
991+
variable, ok := object.(*types.Var)
992+
if !ok {
993+
// Not a local variable.
994+
continue
995+
}
996+
if instr.IsAddr {
997+
// TODO, this may happen for *ssa.Alloc and *ssa.FieldAddr
998+
// for example.
999+
continue
1000+
}
1001+
dbgVar := c.getLocalVariable(frame, variable)
1002+
pos := c.ir.Program.Fset.Position(instr.Pos())
1003+
c.dibuilder.InsertValueAtEnd(c.getValue(frame, instr.X), dbgVar, c.dibuilder.CreateExpression(nil), llvm.DebugLoc{
1004+
Line: uint(pos.Line),
1005+
Col: uint(pos.Column),
1006+
Scope: frame.difunc,
1007+
}, c.builder.GetInsertBlock())
9541008
continue
9551009
}
9561010
if c.DumpSSA() {

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
88
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46
99
go.bug.st/serial v1.0.0
10-
golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef
10+
golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2
11+
google.golang.org/appengine v1.4.0 // indirect
1112
tinygo.org/x/go-llvm v0.0.0-20200104190746-1ff21df33566
1213
)

go.sum

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,25 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
1313
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
1414
go.bug.st/serial v1.0.0 h1:ogEPzrllCsnG00EqKRjeYvPRsO7NJW6DqykzkdD6E/k=
1515
go.bug.st/serial v1.0.0/go.mod h1:rpXPISGjuNjPTRTcMlxi9lN6LoIPxd1ixVjBd8aSk/Q=
16+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
17+
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
18+
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
1619
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
1720
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
21+
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
22+
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
1823
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
24+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
25+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
26+
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1927
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU=
2028
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
2129
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
2230
golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef h1:ymc9FeDom3RIEA3coKokSllBB1hRcMT0tZ1W3Jf9Ids=
2331
golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
32+
golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2 h1:0sfSpGSa544Fwnbot3Oxq/U6SXqjty6Jy/3wRhVS7ig=
33+
golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
34+
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
2435
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
2536
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2637
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

0 commit comments

Comments
 (0)