mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-15 00:13:43 +00:00
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:
committed by
Ron Evans
parent
c8a4994feb
commit
0c73d56861
+68
-14
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user