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.
This commit is contained in:
Ayke van Laethem
2020-01-26 18:59:59 +01:00
committed by Ron Evans
parent c8a4994feb
commit 0c73d56861
3 changed files with 81 additions and 15 deletions
+68 -14
View File
@@ -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() {