debug: supports scope (if, for)

This commit is contained in:
Li Jie
2024-09-29 16:20:41 +08:00
parent e392956e2a
commit 88cb607975
8 changed files with 274 additions and 95 deletions

View File

@@ -93,7 +93,7 @@ def print_all_variables(debugger: lldb.SBDebugger, _command: str, result: lldb.S
frame = debugger.GetSelectedTarget().GetProcess( frame = debugger.GetSelectedTarget().GetProcess(
).GetSelectedThread().GetSelectedFrame() ).GetSelectedThread().GetSelectedFrame()
variables = frame.GetVariables(True, True, True, False) variables = frame.GetVariables(True, True, True, True)
output: List[str] = [] output: List[str] = []
for var in variables: for var in variables:

View File

@@ -107,7 +107,7 @@ class LLDBDebugger:
def get_all_variable_names(self) -> Set[str]: def get_all_variable_names(self) -> Set[str]:
frame = self.process.GetSelectedThread().GetFrameAtIndex(0) frame = self.process.GetSelectedThread().GetFrameAtIndex(0)
return set(var.GetName() for var in frame.GetVariables(True, True, True, False)) return set(var.GetName() for var in frame.GetVariables(True, True, True, True))
def get_current_function_name(self) -> str: def get_current_function_name(self) -> str:
frame = self.process.GetSelectedThread().GetFrameAtIndex(0) frame = self.process.GetSelectedThread().GetFrameAtIndex(0)

View File

@@ -118,26 +118,33 @@ func FuncWithAllTypeParams(
) (int, error) { ) (int, error) {
// Expected: // Expected:
// all variables: i8 i16 i32 i64 i u8 u16 u32 u64 u f32 f64 b c64 c128 slice arr arr2 s e f pf pi intr m c err fn // all variables: i8 i16 i32 i64 i u8 u16 u32 u64 u f32 f64 b c64 c128 slice arr arr2 s e f pf pi intr m c err fn
// i8: '\x01'
// i16: 2
// i32: 3 // i32: 3
// i64: 4 // i64: 4
// i: 5 // i: 5
// u8: '\x06'
// u16: 7
// u32: 8 // u32: 8
// u64: 9 // u64: 9
// u: 10 // u: 10
// f32: 11 // f32: 11
// f64: 12 // f64: 12
// b: true
// c64: complex64{real = 13, imag = 14}
// c128: complex128{real = 15, imag = 16}
// slice: []int{21, 22, 23} // slice: []int{21, 22, 23}
// arr: [3]int{24, 25, 26} // arr: [3]int{24, 25, 26}
// arr2: [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 27}, {i = 28}, {i = 29}} // arr2: [3]github.com/goplus/llgo/cl/_testdata/debug.E{{i = 27}, {i = 28}, {i = 29}}
// s: "hello"
// e: github.com/goplus/llgo/cl/_testdata/debug.E{i = 30} // e: github.com/goplus/llgo/cl/_testdata/debug.E{i = 30}
// i8: '\b'
// i16: 2
// u8: '\x06'
// u16: 7
// b: true
// c64: complex64{real = 13, imag = 14}
// c128: complex128{real = 15, imag = 16}
// s: "hello"
// Expected(skip):
// i8: '\b'
// i16: 2
// u8: '\x06'
// u16: 7
// b: true
println( println(
i8, i16, i32, i64, i, u8, u16, u32, u64, u, i8, i16, i32, i64, i, u8, u16, u32, u64, u,
f32, f64, b, f32, f64, b,
@@ -352,6 +359,63 @@ func FuncStructPtrParams(t *TinyStruct, s *SmallStruct, m *MidStruct, b *BigStru
println("done") println("done")
} }
func ScopeIf(branch int) {
a := 1
// Expected:
// all variables: a branch
// a: 1
if branch == 1 {
b := 2
c := 3
// Expected:
// all variables: a b c branch
// a: 1
// b: 2
// c: 3
// branch: 1
println(a, b, c)
} else {
c := 3
d := 4
// Expected:
// all variables: a c d branch
// a: 1
// c: 3
// d: 4
// branch: 0
println(c, d)
}
// Expected:
// all variables: a branch
// a: 1
println("a:", a)
}
func ScopeFor() {
a := 1
for i := 0; i < 10; i++ {
switch i {
case 0:
println("i is 0")
// Expected:
// all variables: i a
// i: 0
// a: 1
println("i:", i)
case 1:
println("i is 1")
// Expected:
// all variables: i a
// i: 1
// a: 1
println("i:", i)
default:
println("i is", i)
}
}
println("a:", a)
}
func main() { func main() {
FuncStructParams(TinyStruct{I: 1}, SmallStruct{I: 2, J: 3}, MidStruct{I: 4, J: 5, K: 6}, BigStruct{I: 7, J: 8, K: 9, L: 10, M: 11, N: 12, O: 13, P: 14, Q: 15, R: 16}) FuncStructParams(TinyStruct{I: 1}, SmallStruct{I: 2, J: 3}, MidStruct{I: 4, J: 5, K: 6}, BigStruct{I: 7, J: 8, K: 9, L: 10, M: 11, N: 12, O: 13, P: 14, Q: 15, R: 16})
FuncStructPtrParams(&TinyStruct{I: 1}, &SmallStruct{I: 2, J: 3}, &MidStruct{I: 4, J: 5, K: 6}, &BigStruct{I: 7, J: 8, K: 9, L: 10, M: 11, N: 12, O: 13, P: 14, Q: 15, R: 16}) FuncStructPtrParams(&TinyStruct{I: 1}, &SmallStruct{I: 2, J: 3}, &MidStruct{I: 4, J: 5, K: 6}, &BigStruct{I: 7, J: 8, K: 9, L: 10, M: 11, N: 12, O: 13, P: 14, Q: 15, R: 16})
@@ -392,7 +456,7 @@ func main() {
pad2: 200, pad2: 200,
} }
// Expected: // Expected:
// all variables: globalInt globalStruct globalStructPtr s i err // all variables: s i err
// s.i8: '\x01' // s.i8: '\x01'
// s.i16: 2 // s.i16: 2
// s.i32: 3 // s.i32: 3
@@ -419,6 +483,8 @@ func main() {
globalStructPtr = &s globalStructPtr = &s
globalStruct = s globalStruct = s
println("globalInt:", globalInt) println("globalInt:", globalInt)
// Expected(skip):
// all variables: globalInt globalStruct globalStructPtr s i err
println("s:", &s) println("s:", &s)
FuncWithAllTypeStructParam(s) FuncWithAllTypeStructParam(s)
println("called function with struct") println("called function with struct")
@@ -437,14 +503,18 @@ func main() {
s.fn, s.fn,
) )
println(i, err) println(i, err)
println("called function with types") ScopeIf(1)
ScopeIf(0)
ScopeFor()
println(globalStructPtr) println(globalStructPtr)
println(&globalStruct) println(&globalStruct)
s.i8 = 0x12 s.i8 = 0x12
println(s.i8) println(s.i8)
// Expected: // Expected:
// all variables: globalInt globalStruct globalStructPtr s i err // all variables: s i err
// s.i8: '\x12' // s.i8: '\x12'
// Expected(skip):
// globalStruct.i8: '\x01' // globalStruct.i8: '\x01'
println((*globalStructPtr).i8) println((*globalStructPtr).i8)
println("done") println("done")

View File

@@ -238,6 +238,9 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
sig = types.NewSignatureType(nil, nil, nil, params, results, false) sig = types.NewSignatureType(nil, nil, nil, params, results, false)
} }
fn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx, f.Origin() != nil) fn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx, f.Origin() != nil)
if debugSymbols {
fn.Inline(llssa.NoInline)
}
} }
if nblk := len(f.Blocks); nblk > 0 { if nblk := len(f.Blocks); nblk > 0 {
@@ -292,18 +295,6 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
return fn, nil, goFunc return fn, nil, goFunc
} }
func (p *context) getDebugPosition(f *ssa.Function, pos token.Pos) token.Position {
ppos := p.goProg.Fset.Position(pos)
bodyPos := p.getFuncBodyPos(f)
if bodyPos.Filename == "" {
return ppos
}
if ppos.Line < bodyPos.Line {
return bodyPos
}
return ppos
}
func (p *context) getFuncBodyPos(f *ssa.Function) token.Position { func (p *context) getFuncBodyPos(f *ssa.Function) token.Position {
if f.Object() != nil { if f.Object() != nil {
return p.goProg.Fset.Position(f.Object().(*types.Func).Scope().Pos()) return p.goProg.Fset.Position(f.Object().(*types.Func).Scope().Pos())
@@ -311,6 +302,11 @@ func (p *context) getFuncBodyPos(f *ssa.Function) token.Position {
return p.goProg.Fset.Position(f.Pos()) return p.goProg.Fset.Position(f.Pos())
} }
func isGlobal(v *types.Var) bool {
// TODO(lijie): better implementation
return strings.HasPrefix(v.Parent().String(), "package ")
}
func (p *context) debugRef(b llssa.Builder, v *ssa.DebugRef) { func (p *context) debugRef(b llssa.Builder, v *ssa.DebugRef) {
object := v.Object() object := v.Object()
variable, ok := object.(*types.Var) variable, ok := object.(*types.Var)
@@ -322,15 +318,21 @@ func (p *context) debugRef(b llssa.Builder, v *ssa.DebugRef) {
// skip *ssa.FieldAddr // skip *ssa.FieldAddr
return return
} }
if isGlobal(variable) {
// avoid generate local variable debug info of global variable in function
return
}
pos := p.goProg.Fset.Position(v.Pos()) pos := p.goProg.Fset.Position(v.Pos())
value := p.compileValue(b, v.X) value := p.compileValue(b, v.X)
fn := v.Parent() fn := v.Parent()
dbgVar := p.getLocalVariable(b, fn, variable) dbgVar := p.getLocalVariable(b, fn, variable)
scope := variable.Parent()
diScope := b.DIScope(p.fn, scope)
if v.IsAddr { if v.IsAddr {
// *ssa.Alloc // *ssa.Alloc
b.DIDeclare(variable, value, dbgVar, p.fn, pos, b.Func.Block(v.Block().Index)) b.DIDeclare(variable, value, dbgVar, diScope, pos, b.Func.Block(v.Block().Index))
} else { } else {
b.DIValue(variable, value, dbgVar, p.fn, pos, b.Func.Block(v.Block().Index)) b.DIValue(variable, value, dbgVar, diScope, pos, b.Func.Block(v.Block().Index))
} }
} }
@@ -527,10 +529,6 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
} }
log.Panicln("unreachable:", iv) log.Panicln("unreachable:", iv)
} }
if debugSymbols {
pos := p.getDebugPosition(iv.Parent(), iv.Pos())
b.DISetCurrentDebugLocation(p.fn, pos)
}
switch v := iv.(type) { switch v := iv.(type) {
case *ssa.Call: case *ssa.Call:
ret = p.call(b, llssa.Call, &v.Call) ret = p.call(b, llssa.Call, &v.Call)
@@ -698,11 +696,27 @@ func (p *context) jumpTo(v *ssa.Jump) llssa.BasicBlock {
return fn.Block(succs[0].Index) return fn.Block(succs[0].Index)
} }
func (p *context) getDebugLocScope(v *ssa.Function, pos token.Pos) *types.Scope {
if v.Object() == nil {
return nil
}
funcScope := v.Object().(*types.Func).Scope()
return funcScope.Innermost(pos)
}
func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) { func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
if iv, ok := instr.(instrOrValue); ok { if iv, ok := instr.(instrOrValue); ok {
p.compileInstrOrValue(b, iv, false) p.compileInstrOrValue(b, iv, false)
return return
} }
if debugSymbols {
scope := p.getDebugLocScope(instr.Parent(), instr.Pos())
if scope != nil {
diScope := b.DIScope(p.fn, scope)
pos := p.fset.Position(instr.Pos())
b.DISetCurrentDebugLocation(diScope, pos)
}
}
switch v := instr.(type) { switch v := instr.(type) {
case *ssa.Store: case *ssa.Store:
va := v.Addr va := v.Addr
@@ -779,7 +793,8 @@ func (p *context) getLocalVariable(b llssa.Builder, fn *ssa.Function, v *types.V
return b.DIVarParam(p.fn, pos, v.Name(), t, argNo) return b.DIVarParam(p.fn, pos, v.Name(), t, argNo)
} }
} }
return b.DIVarAuto(p.fn, pos, v.Name(), t) scope := b.DIScope(p.fn, v.Parent())
return b.DIVarAuto(scope, pos, v.Name(), t)
} }
func (p *context) compileFunction(v *ssa.Function) (goFn llssa.Function, pyFn llssa.PyObjRef, kind int) { func (p *context) compileFunction(v *ssa.Function) (goFn llssa.Function, pyFn llssa.PyObjRef, kind int) {

View File

@@ -267,6 +267,9 @@ func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObj
} }
sig := fn.Signature sig := fn.Signature
aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false, fn.Origin() != nil) aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false, fn.Origin() != nil)
if debugSymbols {
aFn.Inline(llssa.NoInline)
}
} }
} }
return return

View File

@@ -273,7 +273,8 @@ func (p Function) NewBuilder() Builder {
b := prog.ctx.NewBuilder() b := prog.ctx.NewBuilder()
// TODO(xsw): Finalize may cause panic, so comment it. // TODO(xsw): Finalize may cause panic, so comment it.
// b.Finalize() // b.Finalize()
return &aBuilder{b, nil, p, p.Pkg, prog, make(map[Expr]dbgExpr)} return &aBuilder{b, nil, p, p.Pkg, prog,
make(map[Expr]dbgExpr), make(map[*types.Scope]DIScope)}
} }
// HasBody reports whether the function has a body. // HasBody reports whether the function has a body.
@@ -327,3 +328,23 @@ func (p Function) SetRecover(blk BasicBlock) {
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
type inlineAttr int
const (
NoInline inlineAttr = iota
AlwaysInline
InlineHint
)
func (p Function) Inline(inline inlineAttr) {
inlineAttrName := map[inlineAttr]string{
NoInline: "noinline",
AlwaysInline: "alwaysinline",
InlineHint: "inlinehint",
}[inline]
inlineAttr := p.Pkg.mod.Context().CreateEnumAttribute(llvm.AttributeKindID(inlineAttrName), 0)
p.impl.AddFunctionAttr(inlineAttr)
}
// -----------------------------------------------------------------------------

186
ssa/di.go
View File

@@ -6,6 +6,7 @@ import (
"go/token" "go/token"
"go/types" "go/types"
"path/filepath" "path/filepath"
"unsafe"
"github.com/goplus/llvm" "github.com/goplus/llvm"
) )
@@ -19,6 +20,7 @@ type aDIBuilder struct {
prog Program prog Program
types map[Type]DIType types map[Type]DIType
positioner Positioner positioner Positioner
m llvm.Module // Add this field
} }
type diBuilder = *aDIBuilder type diBuilder = *aDIBuilder
@@ -26,20 +28,21 @@ type diBuilder = *aDIBuilder
func newDIBuilder(prog Program, pkg Package, positioner Positioner) diBuilder { func newDIBuilder(prog Program, pkg Package, positioner Positioner) diBuilder {
m := pkg.mod m := pkg.mod
ctx := m.Context() ctx := m.Context()
m.AddNamedMetadataOperand("llvm.module.flags",
ctx.MDNode([]llvm.Metadata{ b := &aDIBuilder{
llvm.ConstInt(ctx.Int32Type(), 2, false).ConstantAsMetadata(), // Warning on mismatch di: llvm.NewDIBuilder(m),
ctx.MDString("Debug Info Version"), prog: prog,
llvm.ConstInt(ctx.Int32Type(), 3, false).ConstantAsMetadata(), types: make(map[*aType]DIType),
}), positioner: positioner,
) m: m, // Initialize the m field
m.AddNamedMetadataOperand("llvm.module.flags", }
ctx.MDNode([]llvm.Metadata{
llvm.ConstInt(ctx.Int32Type(), 7, false).ConstantAsMetadata(), // Max on mismatch b.addNamedMetadataOperand("llvm.module.flags", 2, "Debug Info Version", 3)
ctx.MDString("Dwarf Version"), b.addNamedMetadataOperand("llvm.module.flags", 7, "Dwarf Version", 5)
llvm.ConstInt(ctx.Int32Type(), 5, false).ConstantAsMetadata(), b.addNamedMetadataOperand("llvm.module.flags", 1, "wchar_size", 4)
}), b.addNamedMetadataOperand("llvm.module.flags", 8, "PIC Level", 2)
) b.addNamedMetadataOperand("llvm.module.flags", 7, "uwtable", 1)
b.addNamedMetadataOperand("llvm.module.flags", 7, "frame-pointer", 1)
// Add llvm.ident metadata // Add llvm.ident metadata
identNode := ctx.MDNode([]llvm.Metadata{ identNode := ctx.MDNode([]llvm.Metadata{
@@ -47,12 +50,19 @@ func newDIBuilder(prog Program, pkg Package, positioner Positioner) diBuilder {
}) })
m.AddNamedMetadataOperand("llvm.ident", identNode) m.AddNamedMetadataOperand("llvm.ident", identNode)
return &aDIBuilder{ return b
di: llvm.NewDIBuilder(m), }
prog: prog,
types: make(map[*aType]DIType), // New method to add named metadata operand
positioner: positioner, func (b diBuilder) addNamedMetadataOperand(name string, intValue int, stringValue string, intValue2 int) {
} ctx := b.m.Context()
b.m.AddNamedMetadataOperand(name,
ctx.MDNode([]llvm.Metadata{
llvm.ConstInt(ctx.Int32Type(), uint64(intValue), false).ConstantAsMetadata(),
ctx.MDString(stringValue),
llvm.ConstInt(ctx.Int32Type(), uint64(intValue2), false).ConstantAsMetadata(),
}),
)
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -225,16 +235,28 @@ func (b diBuilder) createGlobalVariableExpression(scope DIScope, pos token.Posit
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
type aDILexicalBlock struct {
ll llvm.Metadata
}
type DILexicalBlock = *aDILexicalBlock
func (l *aDILexicalBlock) scopeMeta(b diBuilder, pos token.Position) DIScopeMeta {
return &aDIScopeMeta{l.ll}
}
// ----------------------------------------------------------------------------
type aDIVar struct { type aDIVar struct {
ll llvm.Metadata ll llvm.Metadata
} }
type DIVar = *aDIVar type DIVar = *aDIVar
func (b diBuilder) createParameterVariable(f Function, pos token.Position, name string, argNo int, ty DIType) DIVar { func (b diBuilder) createParameterVariable(scope DIScope, pos token.Position, name string, argNo int, ty DIType) DIVar {
return &aDIVar{ return &aDIVar{
ll: b.di.CreateParameterVariable( ll: b.di.CreateParameterVariable(
f.scopeMeta(b, pos).ll, scope.scopeMeta(b, pos).ll,
llvm.DIParameterVariable{ llvm.DIParameterVariable{
Name: name, Name: name,
File: b.file(pos.Filename).ll, File: b.file(pos.Filename).ll,
@@ -513,9 +535,9 @@ func (b diBuilder) diTypeEx(name string, t Type, pos token.Position) DIType {
return ty return ty
} }
func (b diBuilder) varParam(f Function, pos token.Position, varName string, vt DIType, argNo int) DIVar { func (b diBuilder) varParam(scope DIScope, pos token.Position, varName string, vt DIType, argNo int) DIVar {
return b.createParameterVariable( return b.createParameterVariable(
f, scope,
pos, pos,
varName, varName,
argNo, argNo,
@@ -523,8 +545,8 @@ func (b diBuilder) varParam(f Function, pos token.Position, varName string, vt D
) )
} }
func (b diBuilder) varAuto(f Function, pos token.Position, varName string, vt DIType) DIVar { func (b diBuilder) varAuto(scope DIScope, pos token.Position, varName string, vt DIType) DIVar {
return b.createAutoVariable(f, pos, varName, vt) return b.createAutoVariable(scope, pos, varName, vt)
} }
func (b diBuilder) file(filename string) DIFile { func (b diBuilder) file(filename string) DIFile {
@@ -546,21 +568,21 @@ func (b diBuilder) createExpression(ops []uint64) DIExpression {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Copy to alloca'd memory to get declareable address. // Copy to alloca'd memory to get declareable address.
func (b Builder) constructDebugAddr(v Expr) (dbgPtr Expr, dbgVal Expr, deref bool) { func (b Builder) constructDebugAddr(v Expr) (dbgPtr Expr, dbgVal Expr, exists bool) {
if v, ok := b.dbgVars[v]; ok { if v, ok := b.dbgVars[v]; ok {
return v.ptr, v.val, v.deref return v.ptr, v.val, true
} }
t := v.Type.RawType().Underlying() t := v.Type.RawType().Underlying()
dbgPtr, dbgVal, deref = b.doConstructDebugAddr(v, t) dbgPtr, dbgVal = b.doConstructDebugAddr(v, t)
b.dbgVars[v] = dbgExpr{dbgPtr, dbgVal, deref} dbgExpr := dbgExpr{dbgPtr, dbgVal}
return dbgPtr, dbgVal, deref b.dbgVars[v] = dbgExpr
b.dbgVars[dbgVal] = dbgExpr
return dbgPtr, dbgVal, false
} }
func (b Builder) doConstructDebugAddr(v Expr, t types.Type) (dbgPtr Expr, dbgVal Expr, deref bool) { func (b Builder) doConstructDebugAddr(v Expr, t types.Type) (dbgPtr Expr, dbgVal Expr) {
var ty Type var ty Type
switch t := t.(type) { switch t := t.(type) {
case *types.Pointer:
return v, v, false
case *types.Basic: case *types.Basic:
if t.Info()&types.IsComplex != 0 { if t.Info()&types.IsComplex != 0 {
if t.Kind() == types.Complex128 { if t.Kind() == types.Complex128 {
@@ -590,7 +612,7 @@ func (b Builder) doConstructDebugAddr(v Expr, t types.Type) (dbgPtr Expr, dbgVal
dbgPtr.Type = b.Prog.Pointer(v.Type) dbgPtr.Type = b.Prog.Pointer(v.Type)
b.Store(dbgPtr, v) b.Store(dbgPtr, v)
dbgVal = b.Load(dbgPtr) dbgVal = b.Load(dbgPtr)
return dbgPtr, dbgVal, deref return dbgPtr, dbgVal
} }
func (b Builder) di() diBuilder { func (b Builder) di() diBuilder {
@@ -598,13 +620,7 @@ func (b Builder) di() diBuilder {
} }
func (b Builder) DIParam(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) { func (b Builder) DIParam(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) {
ty := v.Type.RawType().Underlying() b.DIValue(variable, v, dv, scope, pos, blk)
if isPtrType(ty) {
expr := b.di().createExpression(nil)
b.di().dbgDeclare(v, dv, scope, pos, expr, blk)
} else {
b.DIValue(variable, v, dv, scope, pos, blk)
}
} }
func (b Builder) DIDeclare(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) { func (b Builder) DIDeclare(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) {
@@ -614,14 +630,13 @@ func (b Builder) DIDeclare(variable *types.Var, v Expr, dv DIVar, scope DIScope,
func (b Builder) DIValue(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) { func (b Builder) DIValue(variable *types.Var, v Expr, dv DIVar, scope DIScope, pos token.Position, blk BasicBlock) {
ty := v.Type.RawType().Underlying() ty := v.Type.RawType().Underlying()
if isPtrType(ty) { if !needConstructAddr(ty) {
expr := b.di().createExpression(nil) expr := b.di().createExpression(nil)
b.di().dbgValue(v, dv, scope, pos, expr, blk) b.di().dbgValue(v, dv, scope, pos, expr, blk)
} else { } else {
dbgPtr, dbgVal, _ := b.constructDebugAddr(v) dbgPtr, _, _ := b.constructDebugAddr(v)
expr := b.di().createExpression([]uint64{opDeref}) expr := b.di().createExpression([]uint64{opDeref})
b.di().dbgValue(dbgPtr, dv, scope, pos, expr, blk) b.di().dbgValue(dbgPtr, dv, scope, pos, expr, blk)
v.impl = dbgVal.impl
} }
} }
@@ -629,25 +644,79 @@ const (
opDeref = 0x06 opDeref = 0x06
) )
func isPtrType(t types.Type) bool { func needConstructAddr(t types.Type) bool {
switch t.(type) { switch t := t.(type) {
case *types.Pointer: case *types.Basic:
return true if t.Info()&types.IsComplex != 0 {
default: return true
} else if t.Info()&types.IsString != 0 {
return true
}
return false return false
case *types.Pointer:
return false
default:
return true
} }
} }
func (b Builder) DIVarParam(f Function, pos token.Position, varName string, vt Type, argNo int) DIVar { func (b Builder) DIVarParam(scope DIScope, pos token.Position, varName string, vt Type, argNo int) DIVar {
t := b.di().diType(vt, pos) t := b.di().diType(vt, pos)
return b.di().varParam(f, pos, varName, t, argNo) return b.di().varParam(scope, pos, varName, t, argNo)
} }
func (b Builder) DIVarAuto(f Function, pos token.Position, varName string, vt Type) DIVar { func (b Builder) DIVarAuto(scope DIScope, pos token.Position, varName string, vt Type) DIVar {
t := b.di().diType(vt, pos) t := b.di().diType(vt, pos)
return b.di().varAuto(f, pos, varName, t) return b.di().varAuto(scope, pos, varName, t)
} }
// hack for types.Scope
type hackScope struct {
parent *types.Scope
children []*types.Scope
number int // parent.children[number-1] is this scope; 0 if there is no parent
elems map[string]types.Object // lazily allocated
pos, end token.Pos // scope extent; may be invalid
comment string // for debugging only
isFunc bool // set if this is a function scope (internal use only)
}
func isFunc(scope *types.Scope) bool {
hs := (*hackScope)(unsafe.Pointer(scope))
return hs.isFunc
}
func (b Builder) DIScope(f Function, scope *types.Scope) DIScope {
if cachedScope, ok := b.diScopeCache[scope]; ok {
return cachedScope
}
pos := b.di().positioner.Position(scope.Pos())
// skip package and universe scope
// if scope.Parent().Parent() == nil {
// return b.di().file(pos.Filename)
// }
var result DIScope
if isFunc(scope) {
// TODO(lijie): should check scope == function scope
result = f
} else {
parentScope := b.DIScope(f, scope.Parent())
result = &aDILexicalBlock{b.di().di.CreateLexicalBlock(parentScope.scopeMeta(b.di(), pos).ll, llvm.DILexicalBlock{
File: b.di().file(pos.Filename).ll,
Line: pos.Line,
Column: pos.Column,
})}
}
b.diScopeCache[scope] = result
return result
}
const (
MD_dbg = 0
)
func (b Builder) DIGlobal(v Expr, name string, pos token.Position) { func (b Builder) DIGlobal(v Expr, name string, pos token.Position) {
if _, ok := b.Pkg.glbDbgVars[v]; ok { if _, ok := b.Pkg.glbDbgVars[v]; ok {
return return
@@ -660,16 +729,16 @@ func (b Builder) DIGlobal(v Expr, name string, pos token.Position) {
v.Type, v.Type,
false, false,
) )
v.impl.AddMetadata(0, gv.ll) v.impl.AddMetadata(MD_dbg, gv.ll)
b.Pkg.glbDbgVars[v] = true b.Pkg.glbDbgVars[v] = true
} }
func (b Builder) DISetCurrentDebugLocation(f Function, pos token.Position) { func (b Builder) DISetCurrentDebugLocation(diScope DIScope, pos token.Position) {
b.impl.SetCurrentDebugLocation( b.impl.SetCurrentDebugLocation(
uint(pos.Line), uint(pos.Line),
uint(pos.Column), uint(pos.Column),
f.scopeMeta(b.di(), pos).ll, diScope.scopeMeta(b.di(), pos).ll,
f.impl.InstructionDebugLoc(), llvm.Metadata{},
) )
} }
@@ -695,6 +764,7 @@ func (b Builder) DebugFunction(f Function, pos token.Position, bodyPos token.Pos
Line: pos.Line, Line: pos.Line,
ScopeLine: bodyPos.Line, ScopeLine: bodyPos.Line,
IsDefinition: true, IsDefinition: true,
LocalToUnit: true,
Optimized: true, Optimized: true,
} }
p.diFunc = &aDIFunction{ p.diFunc = &aDIFunction{

View File

@@ -58,9 +58,8 @@ func (p BasicBlock) Addr() Expr {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
type dbgExpr struct { type dbgExpr struct {
ptr Expr ptr Expr
val Expr val Expr
deref bool
} }
type aBuilder struct { type aBuilder struct {
@@ -70,7 +69,8 @@ type aBuilder struct {
Pkg Package Pkg Package
Prog Program Prog Program
dbgVars map[Expr]dbgExpr dbgVars map[Expr]dbgExpr // save copied address and values for debug info
diScopeCache map[*types.Scope]DIScope // avoid duplicated DILexicalBlock(s)
} }
// Builder represents a builder for creating instructions in a function. // Builder represents a builder for creating instructions in a function.